¿Cómo puedo enviar stdout a múltiples commands?

Hay algunos commands que filtran o actúan sobre la input, y luego la pasan como salida, creo que usualmente para stdout , pero algunos commands solo tomarán el stdin y harán lo que hagan con él, y no generarán nada.

Estoy muy familiarizado con OS X y, por lo tanto, hay dos que me vienen a la mente de inmediato son pbcopy y pbpaste , que son medios para acceder al portapapeles del sistema.

De todos modos, sé que si quiero tomar stdout y escupir la salida para ir tanto a stdout como a un file, entonces puedo usar el command tee . Y sé un poco sobre xargs , pero no creo que sea eso lo que estoy buscando.

Quiero saber cómo puedo dividir stdout para ir entre dos (o más) commands. Por ejemplo:

 cat file.txt | stdout-split -c1 pbcopy -c2 grep -i errors 

Probablemente haya un mejor ejemplo que ese, pero realmente estoy interesado en saber cómo puedo enviar un command estándar que no lo retransmita y, al mismo time, evitar que el stdout sea ​​"silenciado", no estoy preguntando cómo archiva y grep parte de ella y cópiala en el portapapeles; los commands específicos no son tan importantes.

Además, no estoy preguntando cómo enviar esto a un file y stdout , esta puede ser una pregunta "duplicada" (lo siento), pero busqué algunas y solo pude encontrar otras similares que preguntaban cómo dividir entre stdout y file – y las respuestas a esas preguntas parecían ser una tee , que no creo que funcione para mí.

Finalmente, puede preguntar "¿por qué no simplemente hacer que pbcopy sea lo último en la cadena de tuberías?" y mi respuesta es 1) ¿qué sucede si quiero usarlo y todavía veo el resultado en la console? 2) ¿Qué ocurre si quiero usar dos commands que no stdout salida stdout después de procesar la input?

Ah, y una cosa más: me doy count de que podría usar una tee y un tubo con nombre ( mkfifo ) pero esperaba una forma de hacerlo en línea, concisamente, sin una configuration previa 🙂

Solutions Collecting From Web of "¿Cómo puedo enviar stdout a múltiples commands?"

Puede usar tee sustitución en tee y process para esto:

 cat file.txt | tee >(pbcopy) | grep errors 

Esto enviará toda la salida de cat file.txt pbcopy a pbcopy , y solo obtendrás el resultado de grep en tu console.

Puede poner múltiples processs en la parte del tee :

 cat file.txt | tee >(pbcopy) >(do_stuff) >(do_more_stuff) | grep errors 

Puede especificar múltiples nombres de file para tee , y además la salida estándar puede canalizarse en un command. Para enviar la salida a múltiples commands, debe crear varias canalizaciones y especificar cada una de ellas como una salida de tee . Hay varias forms de hacer esto.

Sustitución de processs

Si su caparazón es ksh93, bash o zsh, puede usar la sustitución de processs. Esta es una forma de pasar un conducto a un command que espera un nombre de file. El shell crea el conducto y pasa un nombre de file como /dev/fd/3 al command. El número es el descriptor de file al que está conectado el conducto. Algunas variantes de Unix no son compatibles con /dev/fd ; en estos, una tubería con nombre se utiliza en su lugar (ver más abajo).

 tee >(command1) >(command2) | command3 

Descriptores de files

En cualquier shell POSIX, puede usar múltiples descriptores de files explícitamente. Esto requiere una variante de Unix que admita /dev/fd , ya que todas less una de las salidas de tee deben especificarse por nombre.

 { { { tee /dev/fd/3 /dev/fd/4 | command1 >&9; } 3>&1 | command2 >&9; } 4>&1 | command3 >&9; } 9>&1 

Canalizaciones con nombre

El método más básico y portátil es usar tuberías con nombre . La desventaja es que necesita encontrar un directory que se pueda escribir, crear las tuberías y limpiar después.

 tmp_dir=$(mktemp -d) mkfifo "$tmp_dir/f1" "$tmp_dir/f2" command1 <"$tmp_dir/f1" & pid1=$! command2 <"$tmp_dir/f2" & pid2=$! tee "$tmp_dir/f1" "$tmp_dir/f2" | command3 rm -rf "$tmp_dir" wait $pid1 $pid2 

Solo juega con la sustitución del process.

 mycommand_exec |tee >(grep ook > ook.txt) >(grep eek > eek.txt) 

grep son dos binarys que tienen el mismo resultado de mycommand_exec que su input específica de process.

Si está usando zsh , puede aprovechar la potencia de la function MULTIOS , es decir, deshacerse del command tee completo:

 uname >file1 >file2 

simplemente escribirá el resultado de uname en dos files diferentes: file1 y file2 , lo que es equivalente a uname | tee file1 >file2 uname | tee file1 >file2

De manera similar, networkingirección de inputs estándar

 wc -l <file1 <file2 

es equivalente a cat file1 file2 | wc -l cat file1 file2 | wc -l (tenga en count que esto no es lo mismo que wc -l file1 file2 , el último count el número de líneas en cada file por separado).

Por supuesto, también puede usar MULTIOS para networkingirigir la salida no a files sino a otros processs, utilizando la sustitución de processs, por ejemplo:

 echo abc > >(grep -oa) > >(tr bx) > >(sed 's/c/y/') 

Capture el command STDOUT en una variable y vuelva a utilizarlo tantas veces como desee:

 commandoutput="$(command-to-run)" echo "$commandoutput" | grep -i errors echo "$commandoutput" | pbcopy 

Si necesita capturar STDERR también, entonces use 2>&1 al final del command, así:

 commandoutput="$(command-to-run 2>&1)" 

Para un resultado razonablemente pequeño producido por un command, podemos networkingirigir el resultado al file temporal y enviar esos files temporales a los commands en bucle. Esto puede ser útil cuando el order de los commands ejecutados puede ser importante.

La siguiente secuencia de commands, por ejemplo, podría hacer eso:

 #!/bin/sh temp=$( mktemp ) cat /dev/stdin > "$temp" for arg do eval "$arg" < "$temp" done rm "$temp" 

Prueba ejecutada en Ubuntu 16.04 con /bin/sh como dash :

 $ cat /etc/passwd | ./multiple_pipes.sh 'wc -l' 'grep "root"' 48 root:x:0:0:root:/root:/bin/bash 

Esto puede ser útil: http://www.spinellis.gr/sw/dgsh/ (shell de gráfico dirigido) Parece una sustitución bash que admite una syntax más sencilla para los commands "multipipe".