让ssh在目标计算机的后台执行命令

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

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

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

354998 次浏览

我在一年前写的一个程序中遇到过这个问题——结果发现答案相当复杂。你需要使用nohup以及输出重定向,正如维基百科中关于nohup的文章所解释的那样,为了方便你,这里复制了这篇文章。

Nohuping后台作业是为了 通过SSH登录时有用的例子, 由于后台作业可能导致 Shell在退出时挂起 条件[2]。这个问题也可以 通过重定向这三个方面来克服 I / O流:< / p >

nohup myprogram > foo.out 2> foo.err < /dev/null &

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

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配置随tmux附带,您可以尝试。

我认为你必须把这些答案结合起来才能得到你想要的。如果将nohup与分号结合使用,并将整个内容用引号括起来,那么您将得到:

ssh user@target "cd /some/directory; nohup myprogram > foo.out 2> foo.err < /dev/null"

这似乎对我有用。使用nohup,您不需要附加&到要运行的命令。此外,如果您不需要读取命令的任何输出,则可以使用

ssh user@target "cd /some/directory; nohup myprogram > /dev/null 2>&1"

将所有输出重定向到/dev/null

这对我来说是最干净的方式:-

ssh -n -f user@host "sh -c 'cd /whereever; nohup ./whatever > /dev/null 2>&1 &'"

在此之后唯一运行的是远程计算机上的实际命令

我试图做同样的事情,但增加了复杂性,我试图从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.

这需要一些尝试。错误使此工作,但它现在似乎工作得很好。

首先遵循以下步骤:

以用户A登录A,生成一对认证密钥。不要输入密码:

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创建一个目录~/。(目录可能已经存在,这没有问题):

a@A:~> ssh b@B mkdir -p .ssh
b@B's password:

最后将a的新公钥追加到b@B:。Ssh /authorized_keys最后一次输入b的密码:

a@A:~> cat .ssh/id_rsa.pub | ssh b@B 'cat >> .ssh/authorized_keys'
b@B's password:

从现在开始,你可以以B的身份从A以A的身份登录到B,无需密码:

a@A:~> ssh b@B

这样就可以不用输入密码了

ssh b@B "cd /some/目录;program-to-execute,”

fd的重定向

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

Parantheses

最好的方法是使用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 ) & )"'

我只是想展示一个你可以剪切和粘贴的工作示例:

ssh REMOTE "sh -c \"(nohup sleep 30; touch nohup-exit) > /dev/null &\""

这对我来说很有效:

ssh -x remoteServer "cd yourRemoteDir; ./yourRemoteScript.sh </dev/null >/dev/null 2>&1 & "
我认为这是你需要的: 首先,你需要在你的机器上安装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

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

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

实际上,每当我需要在远程机器上运行复杂的命令时,我喜欢将命令放在目标机器上的脚本中,然后使用ssh运行该脚本。

例如:

# simple_script.sh (located on remote server)


#!/bin/bash


cat /var/log/messages | grep <some value> | awk -F " " '{print $8}'

然后我在源机器上运行这个命令:

ssh user@ip "/path/to/simple_script.sh"

你可以这样做……

sudo /home/script.sh -opt1 > /tmp/script.out &

对我来说,使用tmux new -d <shell cmd>语法创建一个远程 tmux会话似乎非常方便:

ssh someone@elsewhere 'tmux new -d sleep 600'

这将在elsewhere主机上启动新会话,本地机器上的ssh命令将几乎立即返回shell。然后,您可以ssh到远程主机,并将tmux attach连接到该会话。注意,没有本地tmux运行,只有远程运行!

另外,如果你想让你的会话在任务完成后继续,只需在命令后添加一个shell启动器,但不要忘记用引号括起来:

ssh someone@elsewhere 'tmux new -d "~/myscript.sh; bash"'
YOUR-COMMAND &> YOUR-LOG.log &

这应该运行该命令并分配一个进程id,您可以简单地跟踪-f YOUR-LOG.log以查看发生时写入该进程的结果。您可以在任何时候注销,这个过程将继续进行

没有nohup你也可以做到:

ssh user@host 'myprogram >out.log 2>err.log &'

如果你正在使用zsh,那么使用program-to-execute &!是一个特定于zsh的快捷方式来后台和否认进程,这样退出shell会让它继续运行。