How come the ls command prints in multiple columns on tty but only one column everywhere else?

6,408

Solution 1

It is simply detecting that it's output is a terminal device and formatting output so it looks better on it. You can print out the same formatted ls output to a file or pipe with option -C.

How to detect output is a terminal: https://stackoverflow.com/questions/1061575/detect-in-c-if-outputting-to-a-terminal

Solution 2

When the output of a program provides a list of some sort, and you redirect the output of the program to a file, or pipe it to another program, typically it is for the purpose of the second program to read the original program output (or the file), in a loop, 1 line at a time.

In this sort of case, it is almost always more convenient for each line that is read to contain one item (1 filename), or 1 "record" of information about a single item, rather than a number of different items that have to be split apart.

This is especially the case for filenames that can contain spaces because spaces are also the delimiter that separates each item (filename).

For example ...

First, I create some files:

% touch "300"
% cp "300" "301"
% cp "300" "302  304"
% cp "300" "303  305"
% cp "300" "306"
% cp "300" "307"
% cp "300" "308"
% cp "300" "309"
% cp "300" "310  312"
% cp "300" "311  313"
% cp "300" "314  316"
% cp "300" "315  317"
% cp "300" "318"
% cp "300" "319"
% cp "300" "320  322"
% cp "300" "321  323"
% cp "300" "324"
% cp "300" "325"
% cp "300" "bar  bin"
% cp "300" "baz  boo"
% cp "300" "def"
% cp "300" "etc"
% cp "300" "foo  mos"
%

Now, I get a "long" listing of the files I created:

% ls -l
-rw-r--r-- 1 username username 0 Nov 28 01:51 300
-rw-r--r-- 1 username username 0 Nov 28 01:51 301
-rw-r--r-- 1 username username 0 Nov 28 01:51 302  304
-rw-r--r-- 1 username username 0 Nov 28 01:51 303  305
-rw-r--r-- 1 username username 0 Nov 28 01:51 306
-rw-r--r-- 1 username username 0 Nov 28 01:51 307
-rw-r--r-- 1 username username 0 Nov 28 01:51 308
-rw-r--r-- 1 username username 0 Nov 28 01:51 309
-rw-r--r-- 1 username username 0 Nov 28 01:51 310  312
-rw-r--r-- 1 username username 0 Nov 28 01:51 311  313
-rw-r--r-- 1 username username 0 Nov 28 01:51 314  316
-rw-r--r-- 1 username username 0 Nov 28 01:51 315  317
-rw-r--r-- 1 username username 0 Nov 28 01:51 318
-rw-r--r-- 1 username username 0 Nov 28 01:51 319
-rw-r--r-- 1 username username 0 Nov 28 01:51 320  322
-rw-r--r-- 1 username username 0 Nov 28 01:51 321  323
-rw-r--r-- 1 username username 0 Nov 28 01:51 324
-rw-r--r-- 1 username username 0 Nov 28 01:51 325
-rw-r--r-- 1 username username 0 Nov 28 01:51 bar  bin
-rw-r--r-- 1 username username 0 Nov 28 01:51 baz  boo
-rw-r--r-- 1 username username 0 Nov 28 01:51 def
-rw-r--r-- 1 username username 0 Nov 28 01:51 etc
-rw-r--r-- 1 username username 0 Nov 28 01:51 foo  mos
% 

OK, so that is fairly obvious what the filenames are.

Now, I get a listing of the files by columns:

% ls
300  302  304  306  308  310  312  314  316  318  320  322  324  bar  bin  def  foo  mos
301  303  305  307  309  311  313  315  317  319  321  323  325  baz  boo  etc
% 

As you can see, a program reading the output (and even a human observer) would not be able to pick out the correct names of the files and would probably think this is a long list of 3 character filenames.

If we pipe the output of ls into more, we get:

% ls | more
300
301
302  304
303  305
306
307
308
309
310  312
311  313
314  316
315  317
318
319
320  322
321  323
324
325
bar  bin
baz  boo
def
etc
foo  mos
% 

While not very pretty, it is now much easier to pick the correct filenames because each filename is on its own line.

Share:
6,408

Related videos on Youtube

ᔕᖺᘎᕊ
Author by

ᔕᖺᘎᕊ

I'm in my second year of uni in the UK. I'm interested in html, php, javascript, jquery, node.js, python, css, and flutter. I LOVE Chuck!! :D If you need to get in touch with me, see my website for more details. Userscripts I've made some userscripts for the Stack Exchange sites you may be interested in: My SOOF userscript, now Stack Overflow Extras, has a bunch of optional features you can add to 'enhance' SE (examples of these features are: pre-defined edit reasons; side-by-side post editing; highlight answerer's names in comments, and so on) My SE WYSIWYG Editor userscript adds a WYSIWYG (What You See Is What You Get) Editor to Stack Exchange - definitely worth a try! :) My Freehand Circles Drawing Tool userscript allows you to draw directly onto images you see on SE sites - you can change the brush colour and width to draw anything you might want - it's great fun, useful and easy to use :) My Self Destructing Comments userscript allows you to set a date at which a comment you wrote should be deleted - useful for those 'comment cleanup', 'thanks', or 'welcome' comments. My SE Desktop Notifications userscript shows desktop notifications whenever there is new activity on a question open in a new tab - useful for keeping track of questions without having to scroll through the answers to see if there is a new edit, or comment, or score change :) See many more at my Stack Apps profile :) ǝɯɐuɹǝsn ʎɯ ɹoɟ ɯoɔ˙sloqɯʎsɟ˙ʍʍʍ oʇ sʞuɐɥʇ

Updated on September 18, 2022

Comments

  • ᔕᖺᘎᕊ
    ᔕᖺᘎᕊ 4 months

    Even after using Unix-like OSes for a couple years, this behaviour still baffles me.

    When I use the ls command in a directory that has lots of files, the output is usually nicely formatted into multiple columns. Here's an example:

    $ ls
    a.txt  C.txt  f.txt  H.txt  k.txt  M.txt  p.txt  R.txt  u.txt  W.txt  z.txt
    A.txt  d.txt  F.txt  i.txt  K.txt  n.txt  P.txt  s.txt  U.txt  x.txt  Z.txt
    b.txt  D.txt  g.txt  I.txt  l.txt  N.txt  q.txt  S.txt  v.txt  X.txt
    B.txt  e.txt  G.txt  j.txt  L.txt  o.txt  Q.txt  t.txt  V.txt  y.txt
    c.txt  E.txt  h.txt  J.txt  m.txt  O.txt  r.txt  T.txt  w.txt  Y.txt
    

    However, if I try to redirect the output to a file, or pipe it to another command, only a single column appears in the output. Using the same example directory as above, here's what I get when I pipe ls to wc:

    $ ls | wc
         52      52     312
    

    In other words, wc thinks there are 52 lines, even though the output to the terminal has only 5.

    I haven't observed this behaviour in any other command. Would you like to explain this to me?

  • Admin
    Admin about 10 years
    Oh is that it? I see. Thanks for satisfying my curiosity. :)
  • piokuc
    piokuc about 10 years
    No problem. If your curiosity is satisfied then I think you can kindly close the question.