20

I copied a snippet of Bash to background an ssh command executed remotely:

ssh user@remote <<CMD
some process <&- >log 2>error &
CMD

What does <&- do?
My guess is that it is the same as < /dev/null

My next understanding is that the three main file descriptors (stdin, stdout, stderr) need to be closed to prevent:

  1. The job being backgrounded and the script exiting -- conflicting somehow?
  2. When the terminal closes, all processes that are accepting stdin from terminal are closed?
  • Obligatory cross-reference: See What are the shell's control and redirection operators? — although all it says about this operator is that it "can be used to close or duplicate file descriptors" and you should "see the relevant section of your shell's manual". – G-Man Sep 18 '15 at 7:24
  • If I recall correctly, ssh -nNT user@remote 'command' will create a non-interactive SSH session. Append & to background it, prepend nohup to the command to keep it running if your connection dies. – Mark K Cowan Sep 18 '15 at 14:15
  • 1
    @MarkKCowan man ssh suggests that -N disables running a remote command entirely, and a quick test supports that. – Tom Hunt Sep 18 '15 at 15:08
  • Ah yes, I used -nNTR for reverse port forwarding. Ignore the -N and -R then :) – Mark K Cowan Sep 18 '15 at 15:10
30

<&- is not quite the same thing as < /dev/null. <&- closes fd 0, whereas < /dev/null redirects it from the device /dev/null, which never provides any data and always gives EOF on read. The difference is mostly that a read(2) call from a closed FD (the <&- case) will error with EBADF, whereas a call from a null-redirected FD will return no bytes read (end-of-file condition). If your program never reads from stdin, the distinction doesn't matter.

Closing the FDs is good practice if you're backgrounding something, since a backgrounded process will hang if it tries to read anything from TTY. This example doesn't fully handle everything it should, though; ideally there would be a nohup or setsid invocation somewhere, to fully disassociate the background process.

  • So I should use nohup in addition to closing file descriptors? – Eric Francis Sep 17 '15 at 16:31
  • 2
    The most thorough method (which imitates the way programs daemonize themselves) is something like setsid some process <&- >path/to/log 2>path/to/error. The quicker method is something like nohup some process &. – Tom Hunt Sep 17 '15 at 16:34
  • 2
    @EricFrancis: Using nohup make no sense here. nohup prevent process from receiving HUP signal when its control terminal closed. But you didn't have any terminal in this case. – cuonglm Sep 17 '15 at 16:44
  • @TomHunt: The background process didn't hang, the ssh session did. – cuonglm Sep 17 '15 at 16:48
  • 2
    not a good idea to close fds 0, 1 & 2 ... you don't want the next fd created to take up one of those values. better to redirect them to /dev/null – Murray Jensen Sep 19 '15 at 0:01
7

See man bash:

  [n]<&word

is used to duplicate input file descriptors. If word expands to one or more digits, the file descriptor denoted by n is made to be a copy of that file descriptor. If the digits in word do not specify a file descriptor open for input, a redirection error occurs. If word evaluates to -, file descriptor n is closed. If n is not specified, the standard input (file descriptor 0) is used.

  • The correct definition is that it is unspecified what happens when you have [n]<&word and word contains more than a single digit. – schily Sep 17 '15 at 16:57
  • What do you mean? Is the man bash incorrect? – Eric Francis Sep 17 '15 at 18:36
  • @EricFrancis because it is unspecified in the standard, bash chooses to implement it in a sane way (for some suitable definition of "sane"). Other shells may or may not do so. – muru Sep 17 '15 at 18:51
  • @muru The question is tagged bash, not posix-shell. – Barmar Sep 24 '15 at 14:15
  • @Barmar ok. So...? – muru Sep 24 '15 at 14:16
7

<&- close standard input.

The general form, defined by POSIX, is:

[n]<&word

Its purpose to made file descriptor n is a copy of file descriptor denoted by word. Standard in is assumed if n is omitted, and if word is -, the file descriptor n will be closed.

It's not the same as </dev/null, since when in case of </dev/null, the standard input still opened, and was redirected to other place.

You need to closed all file descriptors of processes which were attached to ssh socket, otherwise, ssh session can not close.

You can run the command on remote machine without attach it to ssh session, by using screen or tmux:

ssh user@remote 'screen -S test -d -m command'
  • Why the down vote? – cuonglm Sep 19 '15 at 23:36

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.