我如何知道通过 ssh 运行的命令何时完成?

我如何知道通过 ssh 运行的命令何时完成?

我正在为我的项目制作部署脚本,并且正在制作一个能够在本地和远程(通过 ssh 在服务器上)运行命令并返回文本输出的函数。

运行本地命令时,我可以通过等待命令的 PID 轻松知道该命令是否已完成。当我通过打开的 SSH 连接发送命令时,我会收到输出,但我不知道该命令是否已退出,或者该命令是否仍在运行并将在稍后生成更多输出。

目前,我已经通过为每个命令打开与服务器的新连接来“解决”了这个问题,不用说,这是非常痛苦的慢的

这似乎是一个常见问题,并且可能有一个简单的解决方案,甚至可能是 SSH 内置的某种解决方案,所以我在这里问:通过开放的 SSH 连接,我如何知道我发送的命令是否已完成。如果我能以某种方式收集退出代码,那就太好了。


举一个更具体的例子,这基本上证明了我在 Ruby 中遇到的问题:

io = IO.popen(["ssh", "-q", "my-server"], "r+")

io.write("some command\n")

# Sleep for some arbitrary amount of time, because I don't know when the
# command has finished :(
sleep 1

output = io.readpartial(1_000_000)

io.write("some command\n")

# Sleep for some arbitrary amount of time, because I don't know when the
# command has finished :(
sleep 1

output = io.readpartial(1_000_000)

答案1

将您的命令包装在脚本中,当命令完成时它会通知您。

如果您有一个可用的 SMTP 服务器,可以接受从您的服务器发出的电子邮件,那么您可以使用它。

下面的示例将执行your-command,将其输出和 stderr 捕获到文件中,然后使用malix邮件发送结果。与使用伪变量相比,肯定有更好的方法来确保捕获输出的文件是唯一的$$(也许可以使用生成随机字符串的例程)。

#/bin/bash
your-command > /tmp/$$.$0.output 2>&1
RESULT=$?
echo >> /tmp/$$.$0.output
echo "Exit code $RESULT" >> /tmp/$$.$0.output
cat /tmp/$$.$0.output | mailx -s "your-command has finished with exit code $RESULT." [email protected]
rm /tmp/$$.$0.output

如果你想要一些可以指定命令队列的东西,请查看任务后台处理程序apt-get install tsp在 Debian 上)它允许您从队列中添加和删除命令,我相信甚至可以通过电子邮件向您发送它们的输出。

仔细阅读你的问题...似乎你正在治疗SSH 连接正在输入/输出什么作为原始 I/O 流。

SSH 提供加密管道,并具有一些端口转发功能,除此之外就没有什么其他功能了。连接到该管道的典型东西是 shell,它通常希望另一端有一个交互式用户。

思考 单一用途钥匙可以有点轻松地实现您想要做的事情,但最简单的事情是创建一个执行此操作的小包装脚本:

#/bin/bash
$@ 
echo "==== Command Output Finished ===="

然后在 I/O 例程中查找字符串,==== Command Output Finished ====以确定命令输出之间的边界。当然,您必须选择一些不可能成为命令有效输出的一部分的内容。可以采用更复杂的方案。

SMTP 对其边界标头执行类似操作。

答案2

如果您保留在单独的 SSH 会话中运行每个命令的解决方案,则可以通过使用已打开的连接来加快启动每个会话所需的时间。这意味着您只需支付一次连接开销,从而可以快速启动后续会话。

最简单的设置方法是通过以下命令打开第一个连接:

ssh -M -S /tmp/ssh_mux_%h_%p_%r myserver

然后使用以下命令打开每个后续连接:

ssh -S /tmp/ssh_mux_%h_%p_%r myserver "command"

ssh_config下的手册页或在线有更多信息ControlMasterControlPath这里这里

答案3

这个答案与上面的其他答案类似。但我将通过使用 printf 将命令的输出包装在特殊的 SOT 和 EOT 字符中来解决这个问题。因此,我发送的不是命令,而是(已经替换了 COMMAND):

export COMMAND="find ."
printf "%b%s%b" "\002" "`${COMMAND}`" "\003"

然后当 SOT 和 EOT 字符都到达时,搜索并删除它们。本质上,这与echo "==== Command Output Finished ===="解决方案相同,但可能更稳健一些。

相关内容