Você aprende e lembra o que os vários programas fazem, ou você verifica as man pages.
A descrição de ls
é:
List information about the FILEs (the current directory by default)
onde FILEs se refere à sinopse:
ls [OPTION]... [FILE]...
A parte importante a ser lembrada sobre ls
é que ele gerará informações sobre os "ARQUIVOS" que você der - na linha de comando . O manual não descreve as maneiras pelas quais ls
lê qualquer entrada (de, por exemplo, um pipe).
Compare a página ls
man com, digamos, a página cat
man, que diz:
cat [OPTION]... [FILE]...
Concatenate FILE(s) to standard output. With no FILE, or when FILE is -, read standard input.
Com cat
, você pode cat /some/file
ou pode echo hi | cat
.
Portanto, no seu primeiro exemplo,
find . -maxdepth 2 -type d | ls
find
foi e fez algum trabalho e passou alguns (ou nenhum) nome de diretório em seu stdout, que se tornou stdin de ls
, que ls
prontamente ignorou. Como você forneceu ls
no FILEs para listar, o padrão era listar o diretório atual.
No seu segundo exemplo,
find . -type d | xargs ls
find
foi e fez (mais) funcionar, produzindo todos os diretórios encontrados em seu stdout, que por sua vez foi apresentado a xargs
como stdin. A man page para xargs
lê, em parte:
xargs reads items from the standard input ... and executes the command one or more times ...
então ls
é chamado quantas vezes forem necessárias, dado o número de linhas de entrada no stdin.
A mesma ideia se traduz em seu terceiro comando:
find . -maxdepth 2 -type d | grep home
find
passa qualquer nome de diretório para o stdin de grep
; página do homem do grep diz, novamente em parte:
grep searches the named input FILEs for lines containing a match to the given PATTERN. If no files are specified, or if the file “-” is given, grep searches standard input.
A idéia de um pipeline é simples, mas poderosa, e você simplesmente precisa saber que tipo de saída um programa produz e se um programa pode consumir a entrada em seu stdin.
grep
é uma das ferramentas mais comuns para usar nessas situações. Você pode usá-lo como o comando principal:
grep some-text file1 file2 file3 ...
em cujo caso grep
sabe os nomes dos arquivos, ou você pode enviá-los em sua stdin:
cat file1 file2 file3 ... | grep some-text
... neste caso, grep agora não conhece mais nenhum nome de arquivo ( cat
os conhecia, então produziu seu conteúdo para stdout), e agora o grep não pode saber quais arquivos continham o texto - apenas quais linhas correspondiam. / p>
É tentador encadear um monte de comandos juntos - muitas vezes chamado de "one-liner", muitas vezes semi-facetious, como um "one-liner" pode se tornar longo o suficiente para envolver dois uma segunda linha em uma janela de terminal - - em um "pipeline". Aqui, novamente, você precisa saber exatamente como os programas estão produzindo e consumindo dados.
Dados os arquivos chamados file1
, file2
e file3
, você pode fazer algo como:
find . -name 'file*' | xargs cat
e você não ficará surpreso quando find
produzir os três nomes de arquivos como stdout -
file1
file2
file3
... para o qual xargs compila uma lista e envia para cat
-
cat file1 file2 file3
... quem vê esses três nomes de arquivos e despeja seu conteúdo em sua tela.
Cuidado, então, de um arquivo chamado "file name here"; o comando find
acima será exibido:
file name here
file1
file2
file3
... para o qual xags compila uma lista para cat
-
cat file name here file1 file2 file3
... ao qual cat
reclama (para stderr!):
cat: file: No such file or directory
cat: name: No such file or directory
cat: here: No such file or directory
... seguido pelo conteúdo do arquivo1, arquivo2 e arquivo3.
Agora você está preparado para evitar essa situação usando find ... -exec
ou alternativas como find ... -print0 | xargs -0 ...
para usar NULLs como delimitadores para nomes de arquivos.