Cuando redirige una lista de comandos que contiene una redirección de exec, parece que el exec> / dev / null todavía no se aplica después, como con:
{ exec >/dev/null; } >/dev/null; echo "Hi"
Se imprime "Hola".
Tenía la impresión de que la {}
lista de comandos no se considera una subshell a menos que sea parte de una tubería, por lo exec >/dev/null
que aún debería aplicarse en el entorno de shell actual en mi mente.
Ahora si lo cambia a:
{ exec >/dev/null; } 2>/dev/null; echo "Hi"
no hay salida como se esperaba; el descriptor de archivo 1 sigue apuntando a / dev / null para futuros comandos también. Esto se muestra al volver a ejecutar:
{ exec >/dev/null; } >/dev/null; echo "Hi"
que no dará salida.
Intenté hacer un guión y alinearlo, pero todavía no estoy seguro de qué está sucediendo aquí.
En cada punto de este script, ¿qué está pasando con el descriptor de archivo STDOUT?
EDITAR: Agregar mi salida de strace:
read(255, "#!/usr/bin/env bash\n{ exec 1>/de"..., 65) = 65
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD) = 0
fcntl(1, F_DUPFD, 10) = 10
fcntl(1, F_GETFD) = 0
fcntl(10, F_SETFD, FD_CLOEXEC) = 0
dup2(3, 1) = 1
close(3) = 0
close(10) = 0
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD) = 0
fcntl(1, F_DUPFD, 10) = 10
fcntl(1, F_GETFD) = 0
fcntl(10, F_SETFD, FD_CLOEXEC) = 0
dup2(3, 1) = 1
close(3) = 0
dup2(10, 1) = 1
fcntl(10, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(10) = 0
fstat(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
ioctl(1, TCGETS, 0x7ffee027ef90) = -1 ENOTTY (Inappropriate ioctl for device)
write(1, "hi\n", 3) = 3
fuente
close(10)
. ¿También puede publicar todo el contenido del script en el que ejecutó strace?;
Después de todo}
, tiene un parásito que cambia el significado de> /dev/null
no aplicarse a la lista compuesta{}
.Respuestas:
Vamos a seguir
paso a paso.
Hay dos comandos:
a.
{ exec >/dev/null; } >/dev/null
, seguido porsi.
echo "Hi"
El shell ejecuta primero el comando (a) y luego el comando (b).
La ejecución de los
{ exec >/dev/null; } >/dev/null
ingresos de la siguiente manera:a. Primero, el shell realiza la redirección
>/dev/null
y recuerda deshacerla cuando finaliza el comando .si. Entonces, el shell se ejecuta
{ exec >/dev/null; }
.C. Finalmente, el shell cambia la salida estándar a donde estaba. (Este es el mismo mecanismo que en
ls -lR /usr/share/fonts >~/FontList.txt
- las redirecciones se realizan solo mientras dura el comando al que pertenecen).Una vez que se realiza el primer comando, se ejecuta el shell
echo "Hi"
. La salida estándar es donde estaba antes del primer comando.fuente
Para no utilizar un subconjunto o subproceso, cuando
{}
se canaliza la salida de una lista compuesta>
, el shell guarda el descriptor STDOUT antes de ejecutar la lista compuesta y la restaura después. Por lo tanto,exec >
en la lista compuesta no lleva su efecto más allá del punto donde el descriptor anterior se restablece como STDOUT.Echemos un vistazo a la parte relevante de
strace bash -c '{ exec >/dev/null; } >/dev/null; echo hi' 2>&1 | cat -n
:Puede ver cómo, en la línea 134, el descriptor
1
(STDOUT
) se copia en otro descriptor con índice al menos10
(eso es lo queF_DUPFD
hace; devuelve el descriptor más bajo disponible comenzando en el número dado después de duplicar en ese descriptor). Vea también cómo, en la línea 137, el resultado deopen("/dev/null")
(descriptor3
) se copia en descriptor1
(STDOUT
). Finalmente, en línea147
, el antiguoSTDOUT
guardado en el descriptor10
se copia nuevamente en el descriptor1
(STDOUT
). El efecto neto es aislar el cambio aSTDOUT
en línea144
(que corresponde al interiorexec >/dev/null
).fuente
exec
.La diferencia entre
{ exec >/dev/null; } >/dev/null; echo "Hi"
y{ exec >/dev/null; }; echo "Hi"
es que la doble redirección lo hacedup2(10, 1);
antes de cerrar fd 10, que es la copia del originalstdout
, antes de ejecutar el siguiente comando (echo
).Sucede de esa manera porque la redirección externa está superponiendo la redirección interna. Es por eso que copia el
stdout
fd original una vez que se completa.fuente