When ls
is called, it outputs all the files/directories in the current directory, attempting to fit as many as possible on each line. Why is it that when passed to wc -l
, it outputs the number of files? How does it decide how many lines to output its results in?
2 Answers
When ls
is executed it parses various options. It also detect if output is a tty or not by isatty().
ls.c:
case LS_LS:
/* This is for the `ls' program. */
if (isatty (STDOUT_FILENO))
{
format = many_per_line;
/* See description of qmark_funny_chars, above. */
qmark_funny_chars = true;
}
else
{
format = one_per_line;
qmark_funny_chars = false;
}
break;
...
/* disable -l */
if (format == long_format)
format = (isatty (STDOUT_FILENO) ? many_per_line : one_per_line);
etc.
If you want you can compile a simple test:
isawhat.c
#include <stdio.h>
#include <unistd.h>
int main(void)
{
if (isatty(STDOUT_FILENO)) {
fprintf(stdout, "Word by word my world.\n");
} else {
fprintf(stdout, "HELP! Stranger handling my words!!\n");
}
fprintf(stderr, "Bye bye.\n");
return 0;
}
Compile by:
gcc -o isawhat isawhat.c
Then e.g.:
$ ./isawhat | sed 's/word/world/'
Width is measured in columns. One column is one character. It starts out with 80, then check if the environment variable COLUMNS is set and holds a valid int that is not larger then SIZE_MAX (Which is arch dependant - your terminal will never be that wide (at least not yet)).
Try e.g. echo $COLUMNS
. It most probably reflect the number of columns you have available in the window. As window get resized - this get updated. It most probably also get reset by various commands.
One way to set it a bit harder is by stty
. E.g. stty columns 60
. Use stty -a
to view all (man stty). A fun piece of software.
If compiled in it also query for columns by ioctl(), Window size detect.. By passing the filenumber for stdout to ioctl
and passing the request TIOCGWINSZ the structure winsize
get filled with the number of columns.
This can also be demonstrated by a simple c-code:
Compile, run and resize window. Should update. Ctrl+C to quit.
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <signal.h>
static int run;
void sig_handler(int sig) {
switch (sig) {
case SIGINT:
case SIGTERM:
case SIGSTOP:
run = 0;
break;
}
}
void sig_trap(int sig) {
if ((signal(sig, sig_handler)) == SIG_IGN)
signal(sig, SIG_IGN);
}
int main(void)
{
struct winsize ws;
sig_trap(SIGINT);
sig_trap(SIGTERM);
sig_trap(SIGSTOP);
run = 1;
while (run) {
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
fprintf(stdout, "\r %s: %3d, %s: %d\r",
"Columns", ws.ws_col,
"Rows", ws.ws_row
);
fflush(stdout);
}
usleep(5000);
}
fprintf(stdout, "\n");
return 0;
}

- 28,811
When output is directed into a file descriptor other than a terminal (thus pipe, or file, or the like), ls
behaves as if it was invoked as ls -1
.

- 829,060

- 182
-
3Output always go to stdout. What counts is whether stdout is a terminal or not. That is whether a user reads its output or not. – Stéphane Chazelas Jan 30 '13 at 17:44
ls | cat
to see thatls
's output is different when it detects that its output is redirected. – manatwork Jan 30 '13 at 16:30COLUMNS
environment variable generally afftects the width of screen-formatted output. – tripleee Jan 30 '13 at 16:32ls
is one clear example, as you've found out.wget
will use a dotted progress display, instead of the "animated" progress bar you get in "interactive mode". – njsg Jan 30 '13 at 18:00