21

I have a script I can run locally to remotely start a server:

#!/bin/bash
ssh user@host.com <<EOF
  nohup /path/to/run.sh &
EOF
echo 'done'

After running nohup, it hangs. I have to hit ctrl-c to exit the script.

I've tried adding an explicit exit at the end of the here doc and using "-t" argument for ssh. Neither works. How do I make this script exit immediately?

EDIT: The client is OSX 10.6, server is Ubuntu.

mahemoff
  • 44,526
  • 36
  • 160
  • 222

4 Answers4

18

I think the problem is that nohup can't redirect output when you come in from ssh, it only redirects to nohup.out when it thinks it's connected to a terminal, and I the stdin override you have will prevent that, even with -t.

A workaround might be to redirect the output yourself, then the ssh client can disconnect - it's not waiting for the stream to close. Something like:

nohup /path/to/run.sh > run.log &

(This worked for me in a simple test connecting to an Ubuntu server from an OS X client.)

codeforester
  • 39,467
  • 16
  • 112
  • 140
martin clayton
  • 76,436
  • 32
  • 213
  • 198
  • That worked great, thanks. I actually had tried redirecting INPUT from /dev/null, but didn't think of trying with output! (I've tested this does work fine redirecting to /dev/null too, ie nohup /path/to/run.sh > /dev/null & ) – mahemoff Aug 17 '11 at 19:31
  • I am having a similar issue to the OP. I am ssh-ing from a `csh` script, running commands on a remote, and attempting to send the output back to a variable in the `csh` script. Do you think this is possible? I am having the same error: I am doing `ssh -t -t` and getting the error: `Inappropriate IOCtl for device` – krb686 Mar 03 '15 at 20:36
8

The problem might be that ...

... ssh is respecting the POSIX standard when not closing the session 
if a process is still attached to the tty.

Therefore a solution might be to detach the stdin of the nohup command from the tty:

nohup /path/to/run.sh </dev/null &

See: SSH Hangs On Exit When Using nohup

Yet another approach might be to use ssh -t -t to force pseudo-tty allocation even if stdin isn't a terminal.

man ssh | less -Ip 'multiple -t'

ssh -t -t user@host.com <<EOF
  nohup /path/to/run.sh &
EOF

See: BASH spawn subshell for SSH and continue with program flow

Community
  • 1
  • 1
chad
  • 81
  • 1
  • Thanks. The first one didn't work, same result as before. -t -t *did* work (-t -t), but gave the error "tcgetattr: Inappropriate ioctl for device", which makes sense in light of what the double -t does. I searched around for a way to remove the error (I'd rather do this as cleanly as possible) and couldn't see how to do it with a heredoc. Turns out Martin Clayton's answer solves this, so I left it there. – mahemoff Aug 17 '11 at 19:26
2

Redirecting the stdin of the remote host from a here document while invoking ssh without an explicit command leads to the message: Pseudo-terminal will not be allocated because stdin is not a terminal.

To avoid this message either use ssh's -T switch to tell the remote host there is no need to allocate a pseudo-terminal or explicitly specify a command (such as /bin/sh) for the remote host to execute the commands provided by the here document.

If an explicit command is given to ssh, the default is to provide no login shell in the form of a pseudo-terminal, i. e. there will be no normal login session when a command is specified (see man ssh).

Without a command specified for ssh, on the other hand, the default is to create a pseudo-tty for an interactive login session on the remote host.

- ssh user@host.com <<EOF
+ ssh -T user@host.com <<EOF
+ ssh user@host.com /bin/bash <<EOF

As a rule, ssh -t or even ssh -t -t should only be used if there are commands that expect stdin / stdout to be a terminal (such as top or vim) or if it is necessary to kill the remote shell and its children when the ssh client command finishes execution (see: ssh command unexpectedly continues on other system after ssh terminates).

As far as I can tell, the only way to combine an ssh command that does not allocate a pseudo-tty and a nohup command that writes to nohup.out on the remote host is to let the nohup command execute in a pseudo-terminal not created by the ssh mechanism. This can be done with the script command, for example, and will avoid the tcgetattr: Inappropriate ioctl for device message.

#!/bin/bash
ssh localhost /bin/sh <<EOF
  #0<&-  script -q /dev/null nohup sleep 10 1>&- &
  #0<&- script -q -c "nohup sh -c 'date; sleep 10 1>&- &'" /dev/null  # Linux
  0<&- script -q /dev/null nohup sh -c 'date; sleep 10 1>&- &'        # FreeBSD, Mac OS X
  cat nohup.out
  exit 0
EOF
echo 'done'
exit 0
Community
  • 1
  • 1
tarox
  • 21
  • 1
1

You need to add a exit 0 at the end.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
jschorr
  • 3,034
  • 1
  • 17
  • 20