Soy nuevo en Linux y trato de entender cómo funcionan las redirecciones.
He estado probando varias sintaxis para redirigir stdout
y stderr
al mismo archivo, que no todos producen los mismos resultados.
Por ejemplo, si trato de enumerar 2 archivos que no existen (file1
y file2
) y 2 que sí (foo
y fz
):
Sintaxis #1 (sin redirección):
$ ls file1 foo fz file2
Aquí está el resultado que obtengo en la terminal:
ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo fz
Sintaxis #2:
Ahora, con redirección:
$ ls file1 foo fz file2 > redirect 2>&1
El redirect
El archivo contiene lo mismo que el resultado de la Sintaxis #1:
ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo
fz
Entonces, con las dos sintaxis anteriores, parece que el shell imprime stderr
primero, luego stdout
.
Sintaxis #3:
Ahora, si pruebo con cualquiera de las siguientes sintaxis:
$ ls file1 foo fz file2 > redirect 2> redirect
o
$ ls file1 foo fz file2 2> redirect > redirect
Luego el redirect
archivo contendrá esto:
foo
fz
nnot access file1: No such file or directory
ls: cannot access file2: No such file or directory
Aquí se ve como stdout
se imprime antes de stderr
, pero luego vemos que el comienzo de stderr
está "recortado" por la misma cantidad de caracteres que stdout
.
El stdout
tiene 6 caracteres (foo fz
, retorno de carro incluido), por lo que los primeros 6 caracteres del stderr
(ls: ca
) han sido sobrescritos por stdout
.
Así que en realidad parece stderr
se imprimió primero, y que stdout
luego se imprimió sobre stderr
en lugar de anexarse a él.
Sin embargo, habría tenido más sentido para mí si stderr
había sido completamente borrado y reemplazado con stdout
, en lugar de solo parcialmente overwitted.
Sintaxis #4:
La única forma que he encontrado para corregir la sintaxis n.º 3 es agregar el operador de adición a stdout
:
$ ls file1 foo fz file2 >> redirect 2> redirect
o
$ ls file1 foo fz file2 2> redirect >> redirect
Que produce lo mismo que la Sintaxis #2:
ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo
fz
Este artículo aquí explica que la Sintaxis #3 es incorrecta (presumiblemente, también lo es la Sintaxis #4). Pero por el bien del argumento:¿por qué la Sintaxis #3 es incorrecta? ¿Qué dice exactamente (o no) diciendo) que haga el shell en lugar de la sintaxis n.° 2?
Relacionado:¿Cuál es la diferencia entre $(...) y `...` en Bash?
Además, ¿hay alguna razón por la que la salida siempre muestre stderr
? antes de stdout
?
¡Gracias!
Respuesta aceptada:
Es como ejecutar dos procesos para escribir en el mismo archivo al mismo tiempo... mala idea. Termina con dos identificadores de archivos abiertos diferentes y sus datos pueden distorsionarse (como lo hace en el n. ° 3 anterior). Usar la sintaxis #2 es correcto; hace uno identificador de archivo y apunta tanto a stderr como a stdout al mismo lugar.
En cuanto a que stderr siempre se imprima primero, no existe ninguna regla al respecto. Sospecho con ls
es porque ls
necesita verificar cada entrada en el directorio antes de que realmente pueda indicar que un archivo en particular no existe. Entonces, en lugar de hacer N pases sobre la tabla de directorios, hace un solo pase, verificando todos los argumentos de la línea de comando dados, informa los errores e imprime los archivos que encontró. Otros comandos pueden imprimirse en stderr después de stdout, o incluso alternar entre ellos.