Como canalizar a saída do comando para outros comandos?

83

Exemplo:

ls | echoimprime nada (uma linha em branco, na verdade). Espero que imprima uma lista de arquivos.

ls | grep 'foo', por outro lado, funciona conforme o esperado (imprime arquivos com 'foo' no nome).

O que faço nessas situações é algo como: ls | while read OUT; do echo $OUT; donemas isso é bastante complicado.

Por que a tubulação funciona com alguns comandos, mas não com outros? Como posso contornar esse problema?

Mihai Rotaru
fonte
2
O que você espera ls | echofazer? por que não simplesmente correr ls?
theomega 16/09/10
12
Eu usei o exemplo mais simples que ilustra meu ponto. Na verdade, eu encontrei esse problema quando estava tentando criar uma linha que mostrasse objetos git no armazenamento de objetos e seu tipo. Então, eu canalizei os IDs de objeto git cat-file, mas simplesmente não funcionou. Aparentemente, o eco tem o mesmo comportamento, então eu o usei como exemplo.
Mihai Rotaru
Também observe o comando -n para xargs, que diz quantos argumentos colocar no subcomando. `... xargs -n1 git cat-file`
Rich Homolka

Respostas:

118

Há uma distinção entre argumentos de linha de comando e entrada padrão. Um tubo conectará a saída padrão de um processo à entrada padrão de outro. assim

ls | echo

Conecta a saída padrão de ls à entrada padrão de eco. Tudo bem, certo? Bem, echo ignora a entrada padrão e despeja seus argumentos de linha de comando - que não são, neste caso, - seu próprio stdout. A saída: nada.

Existem algumas soluções nesse caso. Uma é usar um comando que lê stdin e despeja em stdout, como cat.

ls | cat

Irá 'funcionar', dependendo da sua definição de trabalho.

Mas e o caso geral. O que você realmente deseja é converter o stdout de um comando na linha de comando args de outro. Como já foi dito, xargsé a ferramenta auxiliar canônica nesse caso, lendo os argumentos da linha de comando para obter um comando a partir do stdin e construindo comandos para execução.

ls | xargs echo

Você também pode converter isso alguns, usando o comando de substituição $()

echo $(ls)

Também faria o que você quer.

Ambas as ferramentas são essenciais para o shell script, você deve aprender as duas.

Para completar, como você indica na pergunta, a outra maneira básica de converter stdin em args da linha de comando é o readcomando interno do shell . Ele converte "palavras" (palavras definidas pela IFSvariável) em uma variável temp, que você pode usar em qualquer execução de comando.

Rich Homolka
fonte
1
Uma resposta muito útil e informativa, obrigado! Atualmente, estou aprendendo o bash e já vi as notações xargs e $ (*) antes, mas não prestei muita atenção a elas. Agora eu sei o quão importante eles são, e definitivamente vou investigar eles.
Mihai Rotaru
1
xargs pode ter sido o que o OP estava procurando.
Iktys
19

ls | echoimprime apenas uma linha em branco porque echonão lê entrada; o último comando do pipeline é, na verdade, echoque imprime apenas uma linha em branco.

Geralmente:

a | b

garante que a saída de ase torne a entrada de b. Eu sugiro que você leia a Pipelinesseção de man bash.


Se você realmente deseja usar lse echojuntos, aqui estão alguns exemplos (bastante inúteis):

ls | xargs -L 1 echo
echo `ls`
for i in `ls` ; do echo $i ; done
cYrus
fonte
11

Se você deseja echoo lscomando, tente:

ls | xargs echo

Isso será chamado echocom a saída de ls.

Nathan Fellman
fonte
3
Ou ls | xargs -I {} echo {}se você quer que ele seja chamado para cada linha individualmente
Alex Abdugafarov
3

Por que não usar simplesmente:

echo `ls`

Ou muito mais seguro:

echo "`ls -lrt`"
Urbwzrd
fonte
4
Ou até mesmo echo *.
Kazark 10/11/12