I noticed that if I type:

ls --color=auto


ls --color=auto | cat
ls --color=auto > >(cat)

I don't see the same output. Therefore I assume a program has an hability to know whether its STDOUT is piped to something. The question is how does it know?

I checked the ENV vars with env and env | cat but I get the same. The answer is somewhere else. I can't figure out where.

From this question I found that I can use isatty() who provide this function? is it part of the shell or the kernel? By going further I see that this function is part of the POSIX standard.

Now I know I have two processes that can communicate in between them with several mechanism:

  • Exit Code
  • Environment variables
  • System calls

Bash and ls are both programs. Thus they can only use the listed mechanisms to exchange information.

The real question behind this is how does isatty() get the information from bash?

  • @Steven - That's a completely different problem. – AFH Jun 24 '15 at 18:05
  • @AFH not really. With the answer given by Steven, I found that a program will use the POSIX function isatty(). I will need to modify my question into: Is isatty() a function linked to the shell or to the kernel? – nowox Jun 24 '15 at 18:07
  • 1
    @Steven Sorry I was confused and asked a X-Y problem... – nowox Jun 24 '15 at 18:16

The --color option is a feature of the GNU ls program. GNU ls uses the isatty() function to test whether the process's standard output is a TTY. Part of the relevant source code can be seen here:

    case COLOR_OPTION:
        int i;
        if (optarg)
          i = XARGMATCH ("--color", optarg, color_args, color_types);
          /* Using --color with no argument is equivalent to using
             --color=always.  */
          i = color_always;

        print_with_color = (i == color_always
                            || (i == color_if_tty
                                && isatty (STDOUT_FILENO)));

The real question behind this is how does isatty() get the information from bash?

isatty() inspects the file descriptor passed to it to see if the file descriptor represents a TTY (terminal device). The exact way that isatty() works may vary from one system to another. Here is a Darwin implementation from Apple OSX if you're interested:

#include <termios.h>
#include <unistd.h>

    int fd;
    struct termios t;

    return(tcgetattr(fd, &t) != -1);

When you run ls --color=auto, your shell (bash) launches the "ls" program using the shell's own standard input, output, and error as the stdin/out/err for the "ls" process. If you are running interactively, then your shell's stdout is probably a terminal, then ls's standard output will probably be a terminal. When ls calls isatty() to test whether its standard output is a terminal, it will probably succeed.

When you run something like ls --color=auto | cat, your shell does three things:

  1. Create a pipe.
  2. Launch cat with its standard input set to be the pipe.
  3. Launch ls with its standard output set to be the pipe.

A pipe is not a terminal. When ls tests whether its standard output is a tty, the test will fail.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.