Fechando um descritor de arquivo,> & - vs <& -

49

No tutorial do bash que estou lendo, ele diz que se você abrir um descritor de arquivo para leitura, ou seja,

exec 3< echolist

Então você deve fechá-lo assim,

exec 3<&-

No entanto, se você abrir um descritor de arquivo para gravação, ele deverá ser fechado assim:

exec 3>&-

No entanto, quando olho para a Internet, vejo pessoas abrindo arquivos e depois os fechando com isso:

exec 3>&- 

NOTA: quando, de acordo com o tutorial, eles devem estar usando exec 3<&1.

Portanto, minha pergunta é: todos os descritores de arquivo podem ser fechados via exec n>&-onde n é o número do descritor de arquivo? Independentemente de ter sido aberto para leitura, escrita ou ambos?

Jason
fonte
21
A única diferença entre >&-e <&-é o padrão fd quando não especificado ( >&-é 1>&-enquanto <&-está 0<&-). O mesmo para o x>&yqual é o mesmo que x<&yexceto quando xnão é fornecido.
Stéphane Chazelas

Respostas:

48

Você pode fechar o descritor de arquivo usando os dois <&-e >&-, bashanalisará duas sintaxe da mesma forma.

Do arquivo y.tab.c no bashcódigo fonte:

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
fonte
2
Isso também pode ser usado nos <>descritores de arquivo.
CMCDragonkai
11
Não, isso não é possível, mas como em 3>&-ou 3<&-parece fechar o descritor.
CMCDragonkai
11
Esse fechamento <>pode ser feito da mesma maneira.
CMCDragonkai
11
Eu não consigo entender o que você quer dizer. Por favor, dê um exemplo. /
cuonglm 17/02
11
Eu não acho que foi isso que eu quis dizer. Só que um descritor de arquivo de gravação e leitura pode ser fechado usando 3> & - e 3 <& - também.
CMCDragonkai
15

Tanto quanto eu posso ver, exec 3>&-e exec 3<&-são as mesmas e podem ser usados em qualquer descritor de arquivo, independentemente de como ele foi aberto. De acordo com as seções 2.7.6 e 2.7.5 da definição POSIX da linguagem de comando do shell :

2.7.5 Duplicando um descritor de arquivo de entrada

O operador de redirecionamento:

[n] <& palavra

[...RECORTE...]

Se a palavra for avaliada como '-', o descritor de arquivo n ou a entrada padrão, se n não for especificado, deverá ser fechado. Tentativas de fechar um descritor de arquivo que não está aberto não devem constituir um erro. Se a palavra avaliar para outra coisa, o comportamento não será especificado.

2.7.6 Duplicando um descritor de arquivo de saída

O operador de redirecionamento:

[n]> & palavra

[...RECORTE...]

Se a palavra for avaliada como '-', o descritor de arquivo n ou a saída padrão se n não for especificado, será fechado. Tentativas de fechar um descritor de arquivo que não está aberto não devem constituir um erro. Se a palavra avaliar para outra coisa, o comportamento não será especificado.

Observe que nenhum deles especifica nada sobre como o descritor de arquivo n foi aberto originalmente. Isso está de acordo com o fato de que o close (2) não se importa com a maneira como você abriu o arquivo.

Uma rápida descrição do seguinte:

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

contra isso:

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

mostra que nos dois casos, o Bash faz exatamente a mesma coisa.

Dois fatos levemente interessantes

Steven D
fonte
11
A página de manual do bash mencionou o fechamento, citando o seu link: Se a palavra for avaliada como '-', o descritor de arquivo n será fechado.
Studion 22/0318
@studog Obrigado por verificar a fonte! Acho que o que aconteceu aqui é que eu estava procurando uma página de manual local para o Bash 3 e depois vinculada à documentação on-line, que era para o Bash 4. Na documentação antiga do Bash 3, a frase sobre fechamento foi omitida na descrição de [N]>&WORD: git .savannah.gnu.org / cgit / bash.git / tree / doc /…
Steven D
7

Um exemplo para o entendimento do cuonglm de fechar um '<>' FD.

Isso é citado no Advanced Bash-Scripting Guide em 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
fonte