题
这是一个后续问题 如何在 shell 脚本中使用 ssh? 问题。如果我想在远程机器上执行在该机器后台运行的命令,如何让 ssh 命令返回?当我尝试在命令末尾包含与号 (&) 时,它会挂起。该命令的确切形式如下所示:
ssh user@target "cd /some/directory; program-to-execute &"
有任何想法吗?需要注意的一件事是,登录到目标计算机总是会产生一个文本横幅,我有 SSH 密钥设置,因此不需要密码。
解决方案
我在一年前编写的一个程序中遇到了这个问题 - 结果答案相当复杂。您需要使用 nohup 以及输出重定向,如维基百科文章中所述 诺哈普, ,复制于此以方便您使用。
例如,当登录通过SSH登录时,毫无用处的作业很有用,因为背景作业可能会导致外壳由于种族条件而挂在注销上[2]。也可以通过重定向所有三个I/O流来克服此问题:
nohup myprogram > foo.out 2> foo.err < /dev/null &
其他提示
这对我来说是最干净的方法:-
ssh -n -f user@host "sh -c 'cd /whereever; nohup ./whatever > /dev/null 2>&1 &'"
此后唯一运行的是远程计算机上的实际命令
重定向 fd
输出需要重定向 &>/dev/null
它将 stderr 和 stdout 重定向到 /dev/null ,并且是 >/dev/null 2>/dev/null
或者 >/dev/null 2>&1
.
括号
最好的方法是使用 sh -c '( ( command ) & )'
其中命令可以是任何内容。
ssh askapache 'sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'
诺哈普外壳
您还可以直接使用 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 &\""
如果您不/无法保持连接打开,您可以使用 屏幕, ,如果您有权安装它。
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。可以通过以下方式实现类似的效果 多路复用器.
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 配置,您可以尝试。
最快、最简单的方法是使用“at”命令:
ssh user@target “现在-f /home/foo.sh”
我认为你必须结合这些答案才能得到你想要的。如果您将 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 -x remoteServer "cd yourRemoteDir; ./yourRemoteScript.sh </dev/null >/dev/null 2>&1 & "
实际上,每当我需要在远程计算机上运行一个复杂的命令时,我喜欢将该命令放入目标计算机上的脚本中,然后使用 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"
我试图做同样的事情,但由于我试图通过 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.
需要进行一些尝试和错误才能使其正常工作,但现在似乎运行良好。
你可以这样做...
sudo /home/script.sh -opt1 > /tmp/script.out &
对我来说,拥有一个似乎很方便 偏僻的 tmux 会话使用 tmux new -d <shell cmd>
语法如下:
ssh someone@elsewhere 'tmux new -d sleep 600'
这将启动新的会话 elsewhere
本地计算机上的 host 和 ssh 命令几乎会立即返回 shell。然后您可以 ssh 到远程主机并 tmux attach
到那次会议。请注意,本地 tmux 运行没有任何内容,只有远程运行!
另外,如果您希望会话在工作完成后持续存在,只需在命令后添加 shell 启动器,但不要忘记用引号引起来:
ssh someone@elsewhere 'tmux new -d "~/myscript.sh; bash"'
我认为这就是你所需要的:首先你需要安装 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
首先按照以下程序操作:
以用户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 以用户 b 在 B 上创建目录 ~/.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:
从现在开始,您可以从 A 以 b 身份登录 B,无需密码:
a@A:~> ssh b@B
那么无需输入密码即可工作
ssh b@B "cd /some/目录;程序执行&”