执行远程命令,完全脱离ssh连接

LVL*_*ron 59 scripting ssh nohup background-process

我有两台电脑,localpcremoteserver

我需要localpcremoteserver. 它需要做的一件事是启动一个运行数小时的备份脚本。我希望命令localpc“开火”然后完全独立运行remoteserver,就像一localpc开始就不存在一样。

这是我到目前为止所做的:

remoteserver 包含有脚本:

/root/backup.sh
Run Code Online (Sandbox Code Playgroud)

localpc 计划运行这个:

ssh root@remoteserver 'nohup /root/backup.sh' &
Run Code Online (Sandbox Code Playgroud)

我这样做是否正确?有一个更好的方法吗?这样做我会遇到任何麻烦吗?

Gil*_*il' 59

关闭,但不完全是。

独立于任何终端

ssh root@remoteserver '/root/backup.sh </dev/null >/var/log/root-backup.log 2>&1 &'
Run Code Online (Sandbox Code Playgroud)

您需要关闭所有连接到 ssh 套接字的文件描述符,因为只要某个远程进程打开了套接字,ssh 会话就不会关闭。如果您对脚本的输出不感兴趣(大概是因为脚本本身负责写入日志文件),请将其重定向到/dev/null(但请注意,这将隐藏诸如无法启动脚本之类的错误)。

使用nohup在这里没有任何有用的效果。nohup如果程序的控制终端消失,它会安排它运行的程序不接收 HUP 信号,但这里首先没有终端,所以没有什么会突然向进程发送 SIGHUP 信号。此外,nohup将标准输出和标准错误(但不是标准输入)重定向到文件,但前提是它们连接到终端,同样,它们不是。

从终端分离

 aaron@localpc$ ssh root@remoteserver
 root@remoteserver# nohup /root/backup.sh </dev/null &
 nohup: appending output to `nohup.out'
 [1] 12345
 root@remoteserver# exit
 aaron@localpc$ 
Run Code Online (Sandbox Code Playgroud)

使用nohup从它的控制终端,从而脱离脚本,它并没有收到SIGHUP当终端消失。nohup还将脚本的标准输出和标准错误重定向到一个文件,nohup.out如果它们连接到终端则调用;你必须自己处理标准输入。

保持远程终端

如果您想让命令在远程终端中运行但不将其附加到 SSH 会话,请在终端多路复用器中运行它,例如ScreenTmux

ssh root@remoteserver 'screen -S backup -d -m /root/backup.sh'
Run Code Online (Sandbox Code Playgroud)

您可以稍后通过screen -S backup -rd在该机器上以 root 身份调用来重新连接到运行脚本的终端。

自动化一个远程命令

为了稍微提高安全性,不要太广泛地打开直接远程 root 登录。创建一个特殊用途的密钥对,并在/root/.ssh/authorized_keys. 公钥文件的内容是AAAA…== wibble@example.com; 添加以逗号分隔的选项列表,其中包括command="…"指定密钥只能用于执行此特定命令的选项。确保将选项和键都放在一行上。

command="/root/backup.sh </dev/null >/dev/null 2>/dev/null &",no-port-forwarding,no-agent-forwarding,no-x11-forwarding,no-pty,no-user-rc AAAA…== wibble@example.com
Run Code Online (Sandbox Code Playgroud)


enz*_*tib 51

您可能应该screen在远程主机上使用,以获得真正的分离命令:

ssh root@remoteserver screen -d -m ./script
Run Code Online (Sandbox Code Playgroud)


Mic*_*lon 13

从远程登录(如 SSH)运行远程命令的标准方法如下:

nohup command </dev/null >command.log 2>&1 &
Run Code Online (Sandbox Code Playgroud)

如果command是一个负责记录到文件本身的 shell 脚本,那么您可以更改command.log/dev/null. 开始此操作后,请立即注销。

你需要那条线上的一切。

nohup 如果登录会话断开连接,则告诉 shell 不要打扰进程。

</dev/null 告诉它永远不要等待输入

>command.log 告诉它向这个命名的日志文件发送任何消息

2>&1告诉它发送任何 stderr 消息到同一个日志文件。在某些情况下,最好有两个文件,第二个用于收集错误消息,第一个用于收集正常活动消息。这可以更容易地验证一切是否正常工作。

& 告诉它分离这个进程并作为守护进程在后台运行。


小智 12

该线程非常有帮助,但我的解决方案必须有所不同。

我不喜欢屏幕解决方案,因为它会留下我不需要的屏幕进程。重定向和 nohups 使用如下:

ssh root@remoteserver '/root/backup.sh </dev/null >/var/log/root-backup.log 2>&1 &'
Run Code Online (Sandbox Code Playgroud)

与 ssh 命令一起使用时对我不起作用。

我在运行实际脚本的远程机器上创建了一个包装脚本。包装器脚本设置重定向和 nohup。像这样的东西:

backupwrapper.sh:
nohup backup.sh > /dev/null 2>&1 &
Run Code Online (Sandbox Code Playgroud)

然后在我的客户端机器上运行(注意没有重定向):

# ssh remotemachine "backupwrapper.sh"
#
Run Code Online (Sandbox Code Playgroud)

ssh 命令立即返回,连接终止,脚本继续运行。


小智 7

正如Nils 所说,允许 root 通过 ssh 登录存在安全风险。我建议不要在没有日志的机器上运行任何实质性的工作。如果出现任何问题,您会希望收到一些故障排除消息。还有其他答案向您展示了如何做到这一点。但这是我建议完成您所要求的方法。这一切都内置在 sh(1) 中。不需要 GNU 屏幕(虽然我认为这是一个聪明的解决方案)。将此字符串附加到您的命令:>&- 2>&- <&- &>&-意味着关闭标准输出。2>&-意味着关闭标准错误。<&-意味着关闭标准输入。&意味着在后台运行,例如

$ ssh myhost 'sleep 30 >&- 2>&- <&- &'
# ssh returns right away, and your sleep job is running remotely
$
Run Code Online (Sandbox Code Playgroud)