LS Command – Count Number of Lines Outputted by ls

lswc

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?

Best Answer

When ls is executed it parses various options. It also detect if output is a tty or not by isatty().

ls.c:

code

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;

...

code

      /* 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;
}
Related Question