我有 2 台电脑,localpc
并且remoteserver
.
我需要localpc
在 上执行一些命令remoteserver
。它需要做的事情之一是启动一个运行数小时的备份脚本。我希望命令localpc
“启动”,然后完全独立地运行remoteserver
,就像localpc
一开始就不存在一样。
这是我到目前为止所做的:
remoteserver
包含脚本:
/root/backup.sh
localpc
计划运行此:
ssh root@remoteserver 'nohup /root/backup.sh' &
我这样做的方式正确吗?有一个更好的方法吗?我这样做会遇到麻烦吗?
答案1
接近,但不完全是。
独立于任何终端
ssh root@remoteserver '/root/backup.sh </dev/null >/var/log/root-backup.log 2>&1 &'
您需要关闭连接到 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$
用于nohup
将脚本与其控制终端分离,以便它不会收到叹息当终端消失时。nohup
还将脚本的标准输出和标准错误重定向到一个名为的文件(nohup.out
如果它们连接到终端);你必须自己处理标准输入。
保留远程终端
如果您想让命令在远程终端中运行,但不将其附加到 SSH 会话,请在终端多路复用器中运行它,例如屏幕或者多路复用器。
ssh root@remoteserver 'screen -S backup -d -m /root/backup.sh'
screen -S backup -rd
您稍后可以通过在该计算机上以 root 身份调用来重新连接到运行脚本的终端。
自动化一个远程命令
为了获得更好的安全性,不要过于广泛地开放直接远程 root 登录。创建一个专用密钥对并给它一个强制命令/root/.ssh/authorized_keys
。公钥文件的内容是;添加以逗号分隔的选项列表,其中指定该键只能用于执行此特定命令。确保将选项和密钥全部放在一行上。AAAA…== [email protected]
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…== [email protected]
答案2
您可能应该screen
在远程主机上使用,以获得真正的独立命令:
ssh root@remoteserver screen -d -m ./script
答案3
该线程非常有帮助,但我的解决方案必须有所不同。
我不喜欢屏幕解决方案,因为它让我不需要的屏幕进程继续运行。重定向和 nohups 的使用如下:
ssh root@remoteserver '/root/backup.sh </dev/null >/var/log/root-backup.log 2>&1 &'
与 ssh 命令一起使用时对我不起作用。
我在远程计算机上创建了一个运行实际脚本的包装脚本。包装器脚本设置重定向和 nohup。像这样的东西:
backupwrapper.sh:
nohup backup.sh > /dev/null 2>&1 &
然后在我的客户端计算机上运行(注意没有重定向):
# ssh remotemachine "backupwrapper.sh"
#
ssh 命令立即返回,连接终止,脚本继续运行。
答案4
作为尼尔斯 说,允许root通过ssh登录存在安全风险。我建议不要在没有日志的机器上运行任何实质性作业。如果出现任何问题,您会希望收到一些故障排除消息。还有其他答案向您展示如何做到这一点。但我建议您如何完成您所要求的事情。它全部内置于 sh(1) 中。不需要 GNU 屏幕(尽管我认为这是一个聪明的解决方案)。将此字符串附加到您的命令中:>&- 2>&- <&- &
。>&-
表示关闭标准输出。2>&-
意味着关闭stderr。<&-
表示关闭标准输入。&
意味着在后台运行,例如
$ ssh myhost 'sleep 30 >&- 2>&- <&- &'
# ssh returns right away, and your sleep job is running remotely
$