Ayer leí este comentario SO que dice que en el shell (al menos bash
) >&-
“tiene el mismo resultado que” >/dev/null
.
Ese comentario en realidad se refiere a la guía ABS como la fuente de su información. Pero esa fuente dice que el >&-
sintaxis "cierra los descriptores de archivos".
No me queda claro si las dos acciones de cerrar un descriptor de archivo y redirigirlo al dispositivo nulo son totalmente equivalentes. Así que mi pregunta es:¿lo son?
En la superficie, parece que cerrar un descriptor es como cerrar una puerta, ¡pero redirigirlo a un dispositivo nulo es abrir una puerta al limbo! Los dos no me parecen exactamente iguales porque si veo una puerta cerrada, no intentaré tirar nada, pero si veo una puerta abierta asumiré que puedo.
En otras palabras, siempre me he preguntado si >/dev/null
significa que cat mybigfile >/dev/null
en realidad procesaría cada byte del archivo y lo escribiría en /dev/null
que lo olvida. Por otro lado, si el shell encuentra un descriptor de archivo cerrado, tiendo a pensar (pero no estoy seguro) que simplemente no escribirá nada, aunque la pregunta sigue siendo si cat
seguirá leyendo cada byte.
Este comentario dice >&-
y >/dev/null
“debería “Será lo mismo, pero no es una respuesta tan rotunda para mí. Me gustaría tener una respuesta más autorizada con alguna referencia al estándar o al núcleo fuente o no...
Respuesta aceptada:
No, ciertamente no desea cerrar los descriptores de archivo 0, 1 y 2.
Si lo hace, la primera vez que la aplicación abra un archivo, se convertirá en stdin/stdout/stderr…
Por ejemplo, si lo hace:
echo text | tee file >&-
Cuando tee
(al menos algunas implementaciones, como busybox') abre el archivo para escritura, se abrirá en el descriptor de archivo 1 (stdout). Así que tee
escribirá text
dos veces en file
:
$ echo text | strace tee file >&-
[...]
open("file", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 1
read(0, "textn", 8193) = 5
write(1, "textn", 5) = 5
write(1, "textn", 5) = 5
read(0, "", 8193) = 0
exit_group(0) = ?
Se sabe que eso causa vulnerabilidades de seguridad. Por ejemplo:
chsh 2>&-
Y chsh
(una aplicación setuid) puede terminar escribiendo mensajes de error en /etc/passwd
.
Algunas herramientas e incluso algunas bibliotecas intentan protegerse contra eso. Por ejemplo GNU tee
moverá el descriptor de archivo a uno arriba de 2 si los archivos que abre para escritura están asignados 0, 1, 2 mientras que busybox tee
no lo hará.
La mayoría de las herramientas, si no pueden escribir en stdout (porque, por ejemplo, no está abierto), informarán un mensaje de error en stderr (en el idioma del usuario, lo que significa un procesamiento adicional para abrir y analizar archivos de localización...), por lo que ser significativamente menos eficiente y posiblemente hacer que el programa falle.
En cualquier caso, no será más eficiente. El programa seguirá haciendo write()
llamada del sistema. Solo puede ser más eficiente si el programa deja de escribir en stdout/stderr después del primer error write()
llamada al sistema, pero los programas generalmente no hacen eso. Por lo general, salen con un error o siguen intentándolo.