¿Cómo canalizar la salida del comando a otros comandos?

83

Ejemplo:

ls | echono imprime nada (una línea en blanco, en realidad). Esperaría que imprima una lista de archivos.

ls | grep 'foo', por otro lado, funciona como se esperaba (imprime archivos con 'foo' en su nombre).

Lo que hago en estas situaciones es algo así como: ls | while read OUT; do echo $OUT; donepero esto es bastante engorroso.

¿Por qué la tubería funciona con algunos comandos, pero no con otros? ¿Cómo puedo evitar este problema?

Mihai Rotaru
fuente
2
¿Qué esperas ls | echohacer? ¿Por qué no simplemente correr ls?
theomega
12
Usé el ejemplo más simple que ilustra mi punto. En realidad, me encontré con este problema cuando intentaba hacer una línea que mostrara los objetos git en el almacén de objetos y su tipo. Entonces, canalicé las ID de los objetos a git cat-file, pero simplemente no funcionó. Aparentemente, echo tiene el mismo comportamiento, así que lo usé como ejemplo.
Mihai Rotaru
También mire el comando -n para xargs, dice cuántos argumentos poner en el subcomando. `... | xargs -n1 git cat-file`
Rich Homolka

Respuestas:

118

Hay una distinción entre argumentos de línea de comando y entrada estándar. Una tubería conectará la salida estándar de un proceso a la entrada estándar de otro. Entonces

ls | echo

Conecta la salida estándar de ls a la entrada estándar de eco. Bien verdad? Bueno, echo ignora la entrada estándar y volcará sus argumentos de línea de comando, que en este caso no son ninguno, su propio stdout. La salida: nada en absoluto.

Hay algunas soluciones en este caso. Una es usar un comando que lea stdin y vuelque a stdout, como cat.

ls | cat

"Funcionará", dependiendo de cuál sea su definición de trabajo.

Pero qué pasa con el caso general. Lo que realmente desea es convertir stdout de un comando en argumentos de línea de comando de otro. Como otros han dicho, xargses la herramienta auxiliar canónica en este caso, leer sus argumentos de línea de comando para un comando desde su stdin y construir comandos para ejecutar.

ls | xargs echo

También puedes convertir esto un poco, usando el comando de sustitución $()

echo $(ls)

También haría lo que quieras.

Ambas herramientas son bastante básicas para las secuencias de comandos de shell, debe aprender ambas.

Para completar, como se indica en la pregunta, la otra forma básica de convertir stdin a args de línea de comando es el readcomando incorporado del shell . Convierte "palabras" (palabras definidas por la IFSvariable) en una variable temporal, que puede usar en cualquier ejecución de comandos.

Rich Homolka
fuente
1
Una respuesta muy útil e informativa, ¡gracias! Actualmente estoy aprendiendo bash, y he visto xargs y la notación $ (*) antes, pero no les presté mucha atención. Ahora sé cuán importantes son, y definitivamente los investigaré.
Mihai Rotaru
1
Xargs puede haber sido lo que OP estaba buscando.
Iktys
19

ls | echoimprime solo una línea en blanco porque echono lee ninguna entrada; el último comando de la canalización es en realidad echoque imprime nada más que una línea en blanco.

Generalmente:

a | b

se asegura de que la salida de se aconvierta en la entrada de b. Te sugiero que leas la Pipelinessección de man bash.


Si realmente quieres usar lsy echojuntos, aquí hay algunos ejemplos (bastante inútiles):

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

Si quieres echoel lscomando prueba:

ls | xargs echo

Esto llamará echocon la salida de ls.

Nathan Fellman
fuente
3
O ls | xargs -I {} echo {}si desea que se llame para cada línea individualmente
Alex Abdugafarov
3

¿Por qué no simplemente usar:

echo `ls`

O mucho más seguro:

echo "`ls -lrt`"
Urbwzrd
fuente
44
O incluso solo echo *.
Kazark