338

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

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

有任何想法吗?需要注意的一点是,登录到目标机器总是会产生一个文本横幅,并且我设置了SSH密钥,因此不需要密码。

4

17 回答 17

352

我在一年前写的一个程序中遇到了这个问题——结果答案相当复杂。您需要使用 nohup 以及输出重定向,如关于nohup的维基百科文章中所述,为方便起见,复制到此处。

例如,当通过 SSH 登录时,Nohuping 后台作业很有用,因为后台作业可能会导致 shell 由于竞争条件而在注销时挂起 [2]。这个问题也可以通过重定向所有三个 I/O 流来解决:

nohup myprogram > foo.out 2> foo.err < /dev/null &
于 2008-08-26T23:18:41.147 回答
271

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

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

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

于 2010-05-14T02:11:16.513 回答
38

重定向 fd

输出需要重定向&>/dev/null,将 stderr 和 stdout 都重定向到 /dev/null 并且是>/dev/null 2>/dev/nullor的同义词>/dev/null 2>&1

括号

最好的方法是使用sh -c '( ( command ) & )'where 命令是任何东西。

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 ) & )"'
于 2012-03-17T08:09:14.773 回答
26

如果您不/不能保持连接打开,您可以使用screen,如果您有权安装它。

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 配置。

于 2008-08-27T17:00:48.940 回答
18

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

ssh REMOTE "sh -c \"(nohup sleep 30; touch nohup-exit) > /dev/null &\""
于 2012-09-05T19:50:27.570 回答
8

我认为您必须将其中的几个答案结合起来才能得到您想要的。如果您将 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。

于 2008-09-11T14:34:14.843 回答
8

最快最简单的方法是使用“at”命令:

ssh user@target "at now -f /home/foo.sh"
于 2014-07-11T11:19:10.233 回答
6

这可能对我有用:

ssh -x remoteServer "cd yourRemoteDir; ./yourRemoteScript.sh </dev/null >/dev/null 2>&1 & " 
于 2013-07-25T16:01:01.470 回答
6

您可以在没有 nohup 的情况下执行此操作:

ssh user@host 'myprogram >out.log 2>err.log &'
于 2020-02-27T16:19:16.833 回答
2

你可以这样做...

sudo /home/script.sh -opt1 > /tmp/script.out &
于 2019-03-19T11:02:59.747 回答
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"
于 2017-06-13T15:13:05.307 回答
1

使用如下语法进行远程tmux 会话对我来说似乎很方便:tmux new -d <shell cmd>

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"'
于 2019-05-20T14:03:05.210 回答
0

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

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

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.

它需要一些试验和错误才能使其正常工作,但现在似乎运行良好。

于 2010-12-30T21:36:27.513 回答
0
YOUR-COMMAND &> YOUR-LOG.log &    

这应该运行命令并分配一个进程 ID,您可以简单地使用 tail -f YOUR-LOG.log 来查看写入它的结果。您可以随时注销,该过程将继续进行

于 2020-02-21T15:53:10.857 回答
0

如果您使用的是 zsh,那么 useprogram-to-execute &!是一个 zsh 特定的快捷方式,用于后台和取消进程,这样退出 shell 将使其继续运行。

于 2021-10-25T13:15:14.203 回答
-3

首先遵循以下程序:

以用户 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/directory; program-to-execute &"

于 2011-06-24T07:07:10.120 回答
-3

我认为这就是你需要的:首先你需要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
于 2014-01-25T09:41:08.740 回答