总结
我想远程执行一个脚本,该脚本以同步开始(这样,如果准备命令失败,本地 ssh 命令也会失败),然后异步执行,从而终止本地 ssh 命令。
细节
我在远程服务器上有一个脚本,它可以缓慢地下载一个几 GB 的文件。我想使用 ssh remote-server 'nohup /path/to/script 参数' 从本地服务器通过 SSH 启动此脚本,但当我知道该脚本已成功开始下载时,会终止 SSH 连接。一旦启动,SSH 连接就没有任何用处,在下载过程中系统性地失败,并阻止在本地服务器上执行。
我不能只做ssh -f
或者ssh &
因为如果远程脚本没有启动,下载之前的第一个命令失败,或者远程服务器无法访问,我需要命令在本地服务器上失败。
我尝试了各种nohup
技巧screen
。我最接近的是以下方法:
由本地服务器启动:
ssh -t me@remote-server 'screen -S long-download /path/to/download.sh'
或者
ssh -t me@remote-server 'nohup screen -S long-download /path/to/download.sh'
在
download.sh
远程服务器上启动:preliminary-instructions # if anything fails so far then the local server's ssh command should fail synchronously download-command & some-more-checking screen -d long-download # we can now safely end the ssh session
但不知为何screen
还是被杀了……
样本复现代码
在远程服务器上,位于
/path/to/test.sh
:#!/bin/bash # uncomment this line to validate synchronous failure sleep 10 && echo foo >/tmp/bar & screen -d long-download
本地:
ssh -t me@remote-server 'nohup screen -S long-download /path/to/test.sh'
答案1
查看 ssh 子系统。我做了类似的事情,但没有使用脚本(即我使用 a.out/elf 编译的程序)。但我刚刚用 bash 脚本测试了一下,它有效。
来自 ssh 手册页:
-s May be used to request invocation of a subsystem on the remote
system. Subsystems are a feature of the SSH2 protocol which
facilitate the use of SSH as a secure transport for other appli-
cations (eg. sftp(1)). The subsystem is specified as the remote
command.
在客户端上使用 -s(小写)指定子系统
在服务器上的 sshd_config 中添加另一个指向您的脚本的子系统条目。
# override default of no subsystems
Subsystem logger /usr/local/libexec/my-logger.sh
Subsystem sftp /usr/libexec/sftp-server
您的脚本应该像任何其他具有执行权限的文件一样启动。我的示例:
#! /usr/local/bin/bash
logger "testing 1.2.3"
echo "return text from my-logger"
exec 0>&- # close stdin
exec 0<&-
exec 1>&- # close stdout
exec 1<&-
exec 2>&- # close stderr
exec 2<&-
logger "subsystem: nohup new script"
nohup /path/to/another/script/logger2.sh &
logger "subsystem: the subsystem started script is now done"
exit 0
您应该能够返回有用的成功或失败错误文本。ssh 连接(以及 stdin、stdout 和 stderr)在子系统结束它之前一直处于打开状态。子系统可以继续运行,也可以停止运行。
让其他脚本(上面的 logger2.sh)休眠 5-10 分钟,这样您就可以使用 netstat 查看 ssh 连接是否断开,ssh 客户端是否返回到 shell,例如 ps ax 显示脚本仍在后台运行。此脚本可能还需要关闭 fd 等。这只是一个简单的例子。祝你好运。
答案2
替代解决方案对 BostonDriver 的回答:screen -d -m
。
在async-launcher.sh
:
#!/bin/bash
echo connected &&
# preliminary-command &&
screen -S index-fetch -d -m $(cd ${0%/*} && pwd -P)/long-download.sh
sleep 5 # ensure long-download.sh didn't immediately fail
if ((`screen -ls | grep index-fetch | wc -l`)); then
echo ok
else
echo ko
exit 1
fi
并且long-download.sh
可以包含所有的异步命令。
通过简单的 启动ssh me@remote-server /path/to/async-launcher.sh
。还有一个额外的好处:屏幕可以稍后重新连接。