É 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
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?
É 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
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.