Getting ssh to execute a command in the background on target machine
这是shell脚本中如何使用ssh的后续问题?问题。如果我想在远程机器上执行一个在该机器后台运行的命令,如何让ssh命令返回?当我尝试只在命令末尾包含和号(&;)时,它将挂起。命令的确切形式如下:
1 | ssh user@target"cd /some/directory; program-to-execute &" |
有什么想法吗?需要注意的一点是,登录到目标计算机总是会生成一个文本横幅,并且我设置了ssh密钥,因此不需要密码。
我在一年前写的一个程序中遇到了这个问题——结果发现答案相当复杂。您需要使用nohup以及输出重定向,正如在nohup上的wikipedia artcle中所解释的,为了您的方便复制到这里。
Nohuping backgrounded jobs is for
example useful when logged in via SSH,
since backgrounded jobs can cause the
shell to hang on logout due to a race
condition [2]. This problem can also
be overcome by redirecting all three
I/O streams:
1 nohup myprogram > foo.out 2> foo.err < /dev/null &
这是对我来说最干净的方法:
1 | ssh -n -f user@host"sh -c 'cd /whereever; nohup ./whatever > /dev/null 2>&1 &'" |
在这之后唯一运行的是远程机器上的实际命令
重定向FD
输出需要使用
最好的方法是使用
1 | ssh askapache 'sh -c"( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"' |
诺霍普壳牌
您也可以直接使用nohup来启动shell:
1 | ssh askapache 'nohup sh -c"( ( chown -R ask:ask /www/askapache.com &>/dev/null ) & )"' |
尼斯发射
另一个技巧是使用nice启动命令/shell:
1 | ssh askapache 'nice -n 19 sh -c"( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"' |
我只想展示一个可以剪切和粘贴的工作示例:
1 | ssh REMOTE"sh -c "(nohup sleep 30; touch nohup-exit) > /dev/null &"" |
如果您不能/不能保持连接打开,您可以使用屏幕,如果您有权安装它。
1 2 3 | 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
要列出屏幕会话:
1 | screen -ls |
要重新附加会话:
1 | screen -d -r remote-command |
请注意,屏幕还可以在每个会话中创建多个shell。使用TMUX也可以达到类似的效果。
1 2 3 | user@localhost $ tmux user@localhost $ ssh user@target # now inside of a tmux session user@remotehost $ cd /some/directory; program-to-execute & |
分离TMUX会话:ctrl bakbd d
要列出屏幕会话:
1 | tmux list-sessions |
要重新附加会话:
1 | tmux attach <session number> |
默认的tmux控制键"ctrl bakbd"有点难以使用,但有几个示例tmux配置随tmux一起提供,您可以尝试使用。
最快和最简单的方法是使用"at"命令:
ssh user@target"at now -f /home/foo.sh"
我想你得把这些答案结合起来才能得到你想要的。如果将nohup与分号结合使用,并用引号将整个内容括起来,则可以得到:
1 | ssh user@target"cd /some/directory; nohup myprogram > foo.out 2> foo.err < /dev/null" |
这似乎对我有用。使用nohup,不需要将&;附加到要运行的命令。此外,如果不需要读取命令的任何输出,则可以使用
1 | ssh user@target"cd /some/directory; nohup myprogram > /dev/null 2>&1" |
将所有输出重定向到/dev/null。
这对我很有用,五月的时候:
1 | ssh -x remoteServer"cd yourRemoteDir; ./yourRemoteScript.sh </dev/null >/dev/null 2>&1 &" |
实际上,每当我需要在一台复杂的远程机器上运行一个命令时,我喜欢将该命令放入目标机器上的一个脚本中,然后使用ssh运行该脚本。
例如:
1 2 3 4 5 | # simple_script.sh (located on remote server) #!/bin/bash cat /var/log/messages | grep <some value> | awk -F"" '{print $8}' |
然后我在源计算机上运行这个命令:
1 | ssh user@ip"/path/to/simple_script.sh" |
你可以这样做…
1 | sudo /home/script.sh -opt1 > /tmp/script.out & |
我试着做同样的事情,但是增加了复杂性,我试着用Java来做。因此,在运行Java的一台机器上,我试图在另一台机器上运行脚本(在后台)(NoHUP)。
在命令行中,这是有效的:(如果不需要-i keyfile来ssh到主机,则可能不需要它)
1 | ssh -i keyFile user@host bash -c""nohup ./script arg1 arg2 > output.txt 2>&1 &"" |
注意,对于我的命令行,在"-c"后面有一个参数,所有参数都用引号括起来。但要在另一端工作,它仍然需要引号,所以我必须在其中放入转义引号。
从Java,这里是什么工作:
1 2 3 4 | 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. |
这项工作花了一点时间,但现在看来工作得很好。
我想这就是你需要的:首先,您需要在您的机器上安装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
首先遵循以下步骤:
以用户A身份登录并生成一对身份验证密钥。不要输入密码:
1 2 3 4 5 6 7 8 9 10 | a@A:~> ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/a/.ssh/id_rsa): Created directory '/home/a/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/a/.ssh/id_rsa. Your public key has been saved in /home/a/.ssh/id_rsa.pub. The key fingerprint is: 3e:4f:05:79:3a:9f:96:7c:3b:ad:e9:58:37:bc:37:e4 a@A |
现在使用ssh在b上创建一个目录~/.ssh作为用户b(该目录可能已经存在,这很好):
1 2 | a@A:~> ssh b@B mkdir -p .ssh b@B's password: |
最后将a的新公钥附加到b@b:.ssh/授权的密钥,最后输入b的密码:
1 2 | a@A:~> cat .ssh/id_rsa.pub | ssh b@B 'cat >> .ssh/authorized_keys' b@B's password: |
从现在起,您可以从A以B身份登录到B,而不需要密码:
1 | a@A:~> ssh b@B |
这样就不用输入密码了
ssh b@b"cd/some/directory;要执行的程序&;