Precedencia de la redirección stdin y stdout en Bash

9

Mi pregunta es sobre la precedencia de la redirección es bash. Supongamos que tiene un comando:

cmd1 < cmd2 > cmd3

¿Se traduciría a:

(cmd1 < cmd2) > cmd3

O

cmd1 < (cmd2 > cmd3)

Deepak Mittal
fuente

Respuestas:

11

El estándar POSIX especifica que la redirección de shell es de izquierda a derecha; es decir, el orden es significativo:

La construcción 2>&1se usa a menudo para redirigir el error estándar al mismo archivo que la salida estándar. Dado que las redirecciones tienen lugar de principio a fin, el orden de las redirecciones es significativo. Por ejemplo:

ls > foo 2>&1

dirige tanto la salida estándar como el error estándar al archivo foo. Sin embargo:

ls 2>&1 > foo

solo dirige la salida estándar al archivo fooporque el error estándar se duplicó como salida estándar antes de que la salida estándar se dirigiera al archivo foo.

bash opera de acuerdo con esta parte de la norma:

$ ls doesnotexist > foo 2>&1
$ cat foo
ls: cannot access doesnotexist: No such file or directory
$ ls doesnotexist 2>&1 > foo
ls: cannot access doesnotexist: No such file or directory
$ cat foo
$ 

En cuanto a la tubería:

Debido a que la asignación de canalización de entrada estándar o salida estándar, o ambas, tiene lugar antes de la redirección, se puede modificar mediante la redirección. Por ejemplo:

$ command1 2>&1 | command2

envía tanto la salida estándar como el error estándar de command1a la entrada estándar de command2.

Matt Eckert
fuente
Eso supone que el shell Bash es compatible con POSIX.
fpmurphy
1
No lo entiendo. Como dijiste que el orden es de izquierda a derecha, no debería ls > foo 2>&1significar redirigir stdout a foo y luego redirigir stderr a stdout. Entonces esto no debería funcionar. Del mismo modo, el segundo comando debería funcionar. ¿Que me estoy perdiendo aqui?
Deepak Mittal
1
@fpmurphy bashes generalmente compatible con POSIX, excepto en las situaciones descritas aquí , donde el bashcomportamiento predeterminado difiere. Para bashconformar más, puede usar la --posixopción.
Matt Eckert
@dpacmittal El primer ejemplo, ls > foo 2>&1funciona así: primero, la salida estándar se redirige a foo, luego, el error estándar se redirige a la salida estándar, que ahora es el archivo foo. El segundo ejemplo, ls 2>&1 > foofunciona así: el error estándar se redirige a la salida estándar antes de que se redirija la salida estándar foo, por lo que el error estándar se repite localmente en lugar de dirigirse al archivo.
Matt Eckert
44
@dpacmittal .. re ls 2>&1 >foo tal vez puedas pensarlo así. stderr de 'ls' se redirige a stdout. Esto va a pasar! Irá a donde stdout está asignado actualmente , independientemente de las directivas adicionales relacionadas con stdout ... (porque esta es su directiva principal / primera ). Luego viene otra directiva que dice que stdout irá a "foo", y lo hace ... Recuerde: stderr no se transmuta para convertirse en stdout en realidad ... Simplemente va a donde se asignó stdout en el momento de la directiva. (por ejemplo, la terminal)
Peter
4

Supongo que tampoco. Un par de paréntesis significa una subcapa. Pero en este caso, no se iniciará ningún sub-shell debido a la redirección. Bash simplemente alimenta cmd2a stdin y alimenta a stdout cmd3.

Estoy pensando, ¿quieres decir algo así cmd1 | cmd2 | cmd3? Porque su cmd2y cmd3son archivos normales en lugar de "cmds".

MetroWind
fuente