Terminating SSH session executed by bash script

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.


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 its 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.)


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


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, ie 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
链接地址: http://www.djcxy.com/p/97124.html

上一篇: 用ssh检查远程主机上是否存在文件

下一篇: 终止由bash脚本执行的SSH会话