Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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?

share|improve this question

migrated from stackoverflow.com Nov 28 '12 at 4:52

This question came from our site for professional and enthusiast programmers.

add comment

2 Answers

up vote 4 down vote accepted

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: Detect in C if outputting to a terminal

share|improve this answer
    
Oh is that it? I see. Thanks for satisfying my curiosity. :) –  David Lou Nov 27 '12 at 20:08
1  
No problem. If your curiosity is satisfied then I think you can kindly close the question. –  piokuc Nov 27 '12 at 20:11
add comment

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|improve this answer
add comment

Your Answer

 
discard

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