我正在为我的项目制作部署脚本,并且正在制作一个能够在本地和远程(通过 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
答案3
这个答案与上面的其他答案类似。但我将通过使用 printf 将命令的输出包装在特殊的 SOT 和 EOT 字符中来解决这个问题。因此,我发送的不是命令,而是(已经替换了 COMMAND):
export COMMAND="find ."
printf "%b%s%b" "\002" "`${COMMAND}`" "\003"
然后当 SOT 和 EOT 字符都到达时,搜索并删除它们。本质上,这与echo "==== Command Output Finished ===="
解决方案相同,但可能更稳健一些。