Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

How does commands like ls know what its stdout is?

It seems ls is operating different depending on what the target stdout is. For example if I do:

ls /home/matt/tmp 

the result is:

a.txt b.txt c.txt

However if I do

ls /home/matt/tmp | cat

the result is (i.e. new line per result):

a.txt
b.txt
c.txt

The process is passed a file descriptor 1 for stdout right? How does it determine how to format the result? Does the file descriptor reveal information?

share|improve this question
add comment

4 Answers 4

The ls program uses isatty() to know whether fd 1 is a tty or something else (pipe, file, etc…). From man 3 isatty:

int isatty(int fd);

DESCRIPTION
The isatty() function tests whether fd is an open file descriptor referring to a terminal


Updade: Line 1538 in ls.c from coreutils (git revision 43a987e1):

  if (isatty (STDOUT_FILENO))
    {
      format = many_per_line;
      /* See description of qmark_funny_chars, above.  */
      qmark_funny_chars = true;
    }

(many_per_line should be self-descriptive.)

share|improve this answer
add comment

From the OpenBSD ls(1) manual:

By default, ls lists one entry per line to standard output; the exceptions are to terminals or when the -C, -m, or -x options are specified.

Then, later:

-1 (The numeric digit ``one''.) Force output to be one entry per line. This is the default when output is not to a terminal.

[...]

-C Force multi-column output; this is the default when output is to a terminal.

share|improve this answer
add comment

Not an exact answer but an exemplification. In a Bash script you can achieve similar effect with test/[['s -t:

-t FD True if FD is opened on a terminal.

Using it like this:

bash-4.2$ where() { [[ -t 1 ]] && echo 'my output goes to TTY' || echo 'my output is redirected'; }

bash-4.2$ where
my output goes to TTY

bash-4.2$ where | cat
my output is redirected

bash-4.2$ where > test.file
bash-4.2$ cat test.file
my output is redirected
share|improve this answer
add comment

You may execute ls in a pseudo-terminal using the script command, pipe the output of ls to another command and get the same output format as if there was no such piping of the stdout stream, i.e. as if stdout were a terminal (tty).

For the underlying isatty() mechanism already pointed out by Stéphane Gimenez see ls.c.

ls -G /
ls -G / | cat
script -q /dev/null ls -G / | sed $'s/\r$//g' | cat

# tty | cat
# script -q /dev/null tty | cat
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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