Bash: sustitución de procesos y stdin

13

La siguiente línea es obvia:

echo "bla" | foo | bar

¿Pero los que están abajo hacen lo mismo?

echo "bla" | bar <(foo)
echo "bla" | bar < <(foo)

¿Cuál de los fooy barlee "bla" de stdin y por qué?

Quiero decir que, por supuesto, solo puedo codificarlo y verificarlo, pero no estoy seguro de si es un comportamiento definido o si estoy explotando características en las que no debería confiar.

etam1024
fuente

Respuestas:

9

Eso depende del shell y no está documentado AFAICS. En kshy bash, en el primer caso, foocompartirá el mismo stdin que bar. Lucharán por la salida de echo.

Así, por ejemplo, en

$ seq 10000 | paste - <(tr 1 X)'
1       X
2       X042
3       X043
4       X044
5       X045
[...]

Usted ve evidencia que pastelee cada dos bloques de texto de seqla salida de mientras trlee los otros.

Con zsh, obtiene el stdin externo (a menos que sea un terminal y el shell no sea interactivo, en cuyo caso se redirige /dev/null). ksh(donde se originó), zshy bashson los únicos proyectiles tipo Bourne con soporte para la sustitución de procesos AFAIK.

En echo "bla" | bar < <(foo), tenga en cuenta que barstdin será la tubería alimentada por la salida de foo. Ese es un comportamiento bien definido. En ese caso, parece que fooel stdin es la tubería alimentada echoen todos ksh, zshy bash.

Si desea tener un comportamiento constante en los tres shells y estar preparado para el futuro, ya que el comportamiento puede cambiar ya que no está documentado, lo escribiría:

echo bla | { bar <(foo); }

Para estar seguro foo, el stdin también es el conducto de echo(aunque no puedo ver por qué querrías hacer eso). O:

echo bla | bar <(foo < /dev/null)

Para asegurarse de fooque no se lee desde la tubería echo. O:

{ echo bla | bar 3<&- <(foo <&3); } 3<&0

Tener fooel stdin el stdin externo como en las versiones actuales de zsh.

Stéphane Chazelas
fuente
"En ese caso, el stdin de foo es la tubería alimentada por eco en todo ksh, zsh y bash". Has probado esto a mano hace un momento o ¿está documentado en algún lugar?
etam1024
¿"En el primer caso" en la primera línea se refiere a `| foo | bar` o `| bar <(foo) `?
Volker Siegel
4

echo "bla" | foo | bar: La salida de echo "bla"se redirige a foo, cuya salida se redirige a bar.

echo "bla" | bar <(foo): Ese canaliza la salida de echo "bla"a bar. Pero barse ejecuta con un argumento. El argumento es la ruta al descriptor de archivo, donde se enviará la salida de foo. Este argumento se comporta como un archivo que contiene la salida de foo. Entonces, eso no es lo mismo.

echo "bla" | bar < <(foo): Se puede suponer que la salida de se echo "bla"debe enviar a bary toda la declaración es equivalente a la primera. Pero eso no es correcto. Sucede lo siguiente: como la redirección de entrada <se realiza después de la tubería ( |), la sobrescribe . Por echo "bla"lo tanto, no se canaliza a la barra. En cambio, la salida de foose redirige como entrada estándar a bar. Para borrar esto, vea el siguiente comando y salida:

$ echo "bla" | cat < <(echo "foo")
foo

Como veis echo "bla"es reemplazado por echo "foo".

Ahora vea este comando:

$ echo "bar" | cat < <(awk '{printf "%s and foo", $0}')
bar and foo

Entonces echo "bar"se canaliza a awk, que lee stdin y agrega la cadena and fooa la salida. Esta salida se canaliza a cat.

caos
fuente
Y mi pregunta es: "¿Es el hecho de que awklee" bar "un comportamiento definido?"
etam1024
Sí lo es. cmd1 < <(cmd2)se comporta igual que cmd2 | cmd1.
caos
O cmd1 | cmd2 | cmd3es lo mismo quecmd1 | cmd3 < <(cmd2)
caos
3
Si fuera wikipedia, pondría la etiqueta "cita requerida" en sus declaraciones :) El objetivo de mi pregunta es que funciona como usted dice, pero no pude encontrar ninguna documentación al respecto.
etam1024