49

In the bash tutorial I am reading, it says that if you open a file descriptor for reading, i.e.

exec 3< echolist

Then you must close it like this,

exec 3<&-

However, if you open a file descriptor for writing, it must be closed like this:

exec 3>&-

Yet when I look on the internet, I see people opening files and then closing them with this:

exec 3>&- 

NOTE: when, according to the tutorial, they should be using exec 3<&1.

So my question is, can all file descriptors be closed via exec n>&- where n is the file descriptor number? Regardless if it was opened for reading, writing, or both?

  • 21
    The only difference between >&- and <&- is the default fd when not specified (>&- is 1>&- while <&- is 0<&-). Same for x>&y which is the same as x<&y except when x is not provided. – Stéphane Chazelas May 24 '14 at 17:01
48

You can close file descriptor using both <&- and >&-, bash will parse two syntax as the same.

From file y.tab.c in bash source code:

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);
  • 1
    This can be used on <> file descriptors too. – CMCDragonkai Feb 17 '16 at 4:42
  • 1
    No that's not possible, but as in 3>&- or 3<&- appears to close the descriptor. – CMCDragonkai Feb 17 '16 at 9:01
  • 1
    That closing <> can be done via the same ways. – CMCDragonkai Feb 17 '16 at 11:01
  • 1
    I can't get what you mean. Please give an example./ – cuonglm Feb 17 '16 at 11:05
  • 1
    I don't think that's what I meant. Just that a a read write file descriptor can be closed using 3>&- and 3<&- as well. – CMCDragonkai Feb 27 '17 at 8:04
15

As far as I can see, exec 3>&- and exec 3<&- are the same and can be used on any file descriptor, regardless of how it was opened. According to sections 2.7.6 and 2.7.5 of the POSIX definition of the Shell Command Language:

2.7.5 Duplicating an Input File Descriptor

The redirection operator:

[n]<&word

[...SNIP...]

If word evaluates to '-', file descriptor n, or standard input if n is not specified, shall be closed. Attempts to close a file descriptor that is not open shall not constitute an error. If word evaluates to something else, the behavior is unspecified.

2.7.6 Duplicating an Output File Descriptor

The redirection operator:

[n]>&word

[...SNIP...]

If word evaluates to '-', file descriptor n, or standard output if n is not specified, is closed. Attempts to close a file descriptor that is not open shall not constitute an error. If word evaluates to something else, the behavior is unspecified.

Note that neither specifies anything about how file descriptor n was opened originally. This is in line with the fact that close(2) doesn't care about how you opened the file.

A quick strace of the following:

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

versus this:

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

shows that in both cases, Bash does exactly the same thing.

Two Mildly Interesting Facts

  • The bash man page section on duplicating file descriptors does not mention that [n]>&- closes file descriptors.
  • In the Bash code for handling redirects (redir.c) you can find this:

    738      /* XXX - what to do with [N]<&$w- where w is unset or null?  ksh93
    739               closes N. */
    
  • 1
    The bash man page does mentioned closing, quoting your link: If word evaluates to ‘-’, file descriptor n is closed. – studog Mar 22 '18 at 14:27
  • @studog Thanks for checking the source! I think what happened here is I was looking at a local manpage for Bash 3, and then linked to the online documentation, which was for Bash 4. In the old Bash 3 documentation, the phrase about closing was omitted from the description of [N]>&WORD: git.savannah.gnu.org/cgit/bash.git/tree/doc/… – Steven D Mar 22 '18 at 22:06
7

An example for cuonglm's understanding of closing a '<>' FD.

This is quoted from the Advanced Bash-Scripting Guide at 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.