Closing a file descriptor, >&- vs <&-

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);

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. */
    

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.