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.