Cerrar un descriptor de archivo,> & - vs <& -

49

En el tutorial de bash que estoy leyendo, dice que si abres un descriptor de archivo para leer, es decir

exec 3< echolist

Entonces debes cerrarlo así,

exec 3<&-

Sin embargo, si abre un descriptor de archivo para escribir, debe cerrarse así:

exec 3>&-

Sin embargo, cuando busco en Internet, veo personas abriendo archivos y luego cerrándolos con esto:

exec 3>&- 

NOTA: cuando, de acuerdo con el tutorial, deberían estar usando exec 3<&1.

Entonces, mi pregunta es, ¿pueden cerrarse todos los descriptores de archivos a través de exec n>&-donde n es el número del descriptor de archivos? ¿Independientemente de si se abrió para leer, escribir o ambos?

Jason
fuente
21
La única diferencia entre >&-y <&-es el fd predeterminado cuando no se especifica ( >&-es 1>&-while <&-es 0<&-). Lo mismo para lo x>&yque es igual, x<&yexcepto cuando xno se proporciona.
Stéphane Chazelas

Respuestas:

48

Puede cerrar el descriptor de archivo con ambos <&-y >&-, bashanalizará dos sintaxis como la misma.

Del archivo y.tab.c en el bashcódigo fuente:

5385   /* Hack <&- (close stdin) case.  Also <&N- (dup and close). */                
5386   if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND))
5387     return (character);
Cuonglm
fuente
2
Esto también se puede usar en <>descriptores de archivos.
CMCDragonkai
1
No, eso no es posible, pero como 3>&-o 3<&-parece cerrar el descriptor.
CMCDragonkai
1
Ese cierre <>se puede hacer de la misma manera.
CMCDragonkai
1
No puedo entender lo que quieres decir. Por favor, da un
ejemplo
1
No creo que eso sea lo que quise decir. Solo que un descriptor de archivo de lectura y escritura puede cerrarse usando 3> & - y 3 <& - también.
CMCDragonkai
15

Por lo que yo puedo ver, exec 3>&-y exec 3<&-son los mismos y se puede utilizar en cualquier descriptor de archivo, independientemente de la forma en que se abrió. De acuerdo con las secciones 2.7.6 y 2.7.5 de la definición POSIX del lenguaje de comandos de Shell :

2.7.5 Duplicar un descriptor de archivo de entrada

El operador de redireccionamiento:

[n] <& palabra

[...RECORTE...]

Si la palabra se evalúa como '-', se cerrará el descriptor de archivo n, o la entrada estándar si no se especifica n. Los intentos de cerrar un descriptor de archivo que no esté abierto no constituirán un error. Si la palabra se evalúa como algo diferente, el comportamiento no se especifica.

2.7.6 Duplicar un descriptor de archivo de salida

El operador de redireccionamiento:

[n]> y palabra

[...RECORTE...]

Si la palabra se evalúa como '-', se cierra el descriptor de archivo n, o la salida estándar si no se especifica n. Los intentos de cerrar un descriptor de archivo que no esté abierto no constituirán un error. Si la palabra se evalúa como algo diferente, el comportamiento no se especifica.

Tenga en cuenta que ninguno especifica nada sobre cómo se abrió originalmente el descriptor de archivo n. Esto está en línea con el hecho de que close (2) no se preocupa por cómo abrió el archivo.

Un fragmento rápido de lo siguiente:

exec 3< /etc/passwd
exec 4> foo
exec 3<&-
exec 4<&-

versus esto:

exec 3< /etc/passwd
exec 4> foo
exec 3<&-
exec 4>&-

muestra que en ambos casos, Bash hace exactamente lo mismo.

Dos hechos levemente interesantes

Steven D
fuente
1
La página de manual de bash menciona el cierre, citando su enlace: Si la palabra se evalúa como '-', el descriptor de archivo n está cerrado.
studog
@studog ¡Gracias por consultar la fuente! Creo que lo que sucedió aquí es que estaba buscando una página de manual local para Bash 3, y luego vinculada a la documentación en línea, que era para Bash 4. En la documentación anterior de Bash 3, la frase sobre el cierre se omitió de la descripción de [N]>&WORD: git .savannah.gnu.org / cgit / bash.git / tree / doc / ...
Steven D
7

Un ejemplo para la comprensión de cuonglm de cerrar un '<>' FD.

Esto se cita de la Guía avanzada de secuencias de comandos Bash en http://tldp.org/LDP/abs/html/io-redirection.html

[j]<>filename
  #  Open file "filename" for reading and writing,
  #+ and assign file descriptor "j" to it.
  #  If "filename" does not exist, create it.
  #  If file descriptor "j" is not specified, default to fd 0, stdin.
  #
  #  An application of this is writing at a specified place in a file. 
  echo 1234567890 > File    # Write string to "File".
  exec 3<> File             # Open "File" and assign fd 3 to it.
  read -n 4 <&3             # Read only 4 characters.
  echo -n . >&3             # Write a decimal point there.
  exec 3>&-                 # Close fd 3.
  cat File                  # ==> 1234.67890
  #  Random access, by golly.
DMW
fuente