Como é que o comando ls imprime em várias colunas em tty mas apenas uma coluna em todo o lado?

3

Mesmo depois de usar sistemas operacionais Unix por alguns anos, esse comportamento ainda me deixa perplexo.

Quando eu uso o comando ls em um diretório que possui muitos arquivos, a saída normalmente é bem formatada em várias colunas. Aqui está um exemplo:

$ 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

No entanto, se eu tentar redirecionar a saída para um arquivo ou canalizá-lo para outro comando, apenas uma única coluna aparecerá na saída. Usando o mesmo diretório de exemplo acima, aqui está o que eu recebo quando canudo ls para wc:

$ ls | wc
     52      52     312

Em outras palavras, achamos que existem 52 linhas, mesmo que a saída para o terminal tenha apenas 5.

Eu não observei esse comportamento em nenhum outro comando. Você gostaria de me explicar isso?

    
por ᔕᖺᘎᕊ 27.11.2012 / 20:59

2 respostas

8

É simplesmente detectar que a saída é um dispositivo terminal e formatar a saída para ficar melhor. Você pode imprimir a mesma saída ls formatada em um arquivo ou pipe com a opção -C.

Como detectar a saída é um terminal: link

    
por 27.11.2012 / 21:03
4

Quando a saída de um programa fornece uma lista de algum tipo, e você redireciona a saída do programa para um arquivo, ou canaliza-o para outro programa, normalmente é para o propósito do segundo programa ler o programa original. saída (ou o arquivo), em um loop, 1 linha por vez.

Nesse tipo de caso, é quase sempre mais conveniente que cada linha lida contenha um item (1 nome de arquivo) ou 1 "registro" de informações sobre um único item, em vez de um número de itens diferentes que tem que ser dividido.

Este é especialmente o caso de nomes de arquivos que podem conter espaços, porque os espaços também são o delimitador que separa cada item (nome do arquivo).

Por exemplo ...

Primeiro, crio alguns arquivos:

% 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"
%

Agora, recebo uma listagem "longa" dos arquivos que criei:

% 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, isso é bastante óbvio quais são os nomes dos arquivos.

Agora, obtenho uma listagem dos arquivos por colunas:

% 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
% 

Como você pode ver, um programa que lê a saída (e até mesmo um observador humano) não seria capaz de escolher os nomes corretos dos arquivos e provavelmente pensaria que esta é uma longa lista de nomes de arquivos de 3 caracteres.

Se canalizarmos a saída de ls para mais, obtemos:

% 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
% 

Embora não seja muito bonito, agora é muito mais fácil escolher os nomes corretos porque cada nome de arquivo está em sua própria linha.

    
por 28.11.2012 / 09:13

Tags