这是一个后续的问题,你如何使用ssh在一个shell脚本?的问题。如果我想在远程机器上执行在后台运行的命令,如何返回ssh命令?当我试图在命令末尾只包含&号时,它就挂起了。命令的确切形式如下所示:

ssh user@target "cd /some/directory; program-to-execute &"

什么好主意吗?需要注意的一件事是,登录到目标机器总是产生一个文本横幅,我设置了SSH密钥,所以不需要密码。


当前回答

如果你不能/不能保持连接打开,你可以使用屏幕,如果你有权限安装它。

user@localhost $ screen -t remote-command
user@localhost $ ssh user@target # now inside of a screen session
user@remotehost $ cd /some/directory; program-to-execute &

分离屏幕会话:ctrl-a d

列出屏幕会话:

screen -ls

重新连接一个会话:

screen -d -r remote-command

注意,screen还可以在每个会话中创建多个shell。使用tmux也可以达到类似的效果。

user@localhost $ tmux
user@localhost $ ssh user@target # now inside of a tmux session
user@remotehost $ cd /some/directory; program-to-execute &

卸载tmux会话:ctrl-b d

列出屏幕会话:

tmux list-sessions

重新连接一个会话:

tmux attach <session number>

默认的tmux控制键'ctrl-b'使用起来有些困难,但有几个tmux配置的示例,您可以尝试。

其他回答

我试图做同样的事情,但增加了复杂性,我试图从Java来做。因此,在一台运行java的机器上,我试图在另一台机器上运行一个脚本,在后台(使用nohup)。

从命令行,这里是工作的:(如果你不需要ssh到主机,你可能不需要“-i keyFile”)

ssh -i keyFile user@host bash -c "\"nohup ./script arg1 arg2 > output.txt 2>&1 &\""

请注意,在我的命令行中,“-c”后面有一个参数,全部用引号括起来。但是为了让它在另一端工作,它仍然需要引号,所以我必须在其中添加转义引号。

从java,这是什么工作:

ProcessBuilder b = new ProcessBuilder("ssh", "-i", "keyFile", "bash", "-c",
 "\"nohup ./script arg1 arg2 > output.txt 2>&1 &\"");
Process process = b.start();
// then read from process.getInputStream() and close it.

它花了一些试验和错误来让它工作,但现在似乎工作得很好。

fd的重定向

输出需要用&>/dev/null重定向,它将stderr和stdout重定向到/dev/null,是>/dev/null 2>/dev/null或>/dev/null 2>&1的同义词。

偏执狂

最好的方法是使用sh -c '((command) &)',其中command是任何东西。

ssh askapache 'sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'

Nohup壳

你也可以使用nohup直接启动shell:

ssh askapache 'nohup sh -c "( ( chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'

漂亮的发射

另一个技巧是使用nice来启动命令/shell:

ssh askapache 'nice -n 19 sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'

@cmcginty简洁的工作示例的后续内容,该示例还展示了如何用双引号替换外部命令。这是在PowerShell脚本中调用模板的样子(该脚本只能从双引号中插入变量,而忽略单引号中包装的任何变量展开):

ssh user@server "sh -c `"($cmd) &>/dev/null </dev/null &`""

内双引号用反标记而不是反斜杠进行转义。这允许$cmd由PowerShell脚本组成,例如用于部署脚本和自动化等。如果使用unix LF组合,$cmd甚至可以包含多行heredoc。

最快和最简单的方法是使用'at'命令:

ssh user@target "at now -f /home/foo.sh"

我认为这是你需要的: 首先,您需要在您的机器上安装sshpass。 然后你可以编写自己的脚本:

while read pass port user ip; do
sshpass -p$pass ssh -p $port $user@$ip <<ENDSSH1
    COMMAND 1
    .
    .
    .
    COMMAND n
ENDSSH1
done <<____HERE
    PASS    PORT    USER    IP
      .      .       .       .
      .      .       .       .
      .      .       .       .
    PASS    PORT    USER    IP    
____HERE