在 bash 脚本中将 SSH 输出捕获为变量

Posted

技术标签:

【中文标题】在 bash 脚本中将 SSH 输出捕获为变量【英文标题】:Capturing SSH output as variable in bash script 【发布时间】:2012-08-16 10:43:48 【问题描述】:

在编写 bash 脚本时,我一直在努力解决这个问题。 基本上,我想测量远程服务器上程序的时间,所以我使用命令: /usr/bin/time -f %e sh -c "my command > /dev/null 2>&1" 执行程序。 但是,似乎我根本无法将命令 (SSH) 的输出捕获到变量中。事实上,结果(时间)不断被打印到标准输出。

完整代码为:

respond=$(ssh $fromNode /usr/bin/time "-f" "%e" "'sh' '-c' 'virsh migrate --live $VM qemu+ssh://$toNode/system --verbose > /dev/null 2>&1'")

response 的值只是空的,虽然时间被打印到标准输出。

【问题讨论】:

superuser.com/questions/130443/… 如果你想将一个mysql查询的结果捕获到一个数组中,你可以这样做:***.com/a/57061108/470749 【参考方案1】:

"time" 命令将结果打印到标准错误,而不是标准输出。因此它不会通过管道传输到您的变量中。

您应该将 stderr 重新路由到 stdout 以实现您想要的:

 result=$(ssh host time "command" 2>&1)

您的完整代码可能如下所示:

 respond=$(ssh $fromNode /usr/bin/time "-f" "%e" "'sh' '-c' 'virsh migrate --live $VM qemu+ssh://$toNode/system > /dev/null 2>&1'" 2>&1)

【讨论】:

太棒了。完全按照我的意愿工作。非常感谢您的大力帮助!顺便说一句,我只是简单地将 &> /dev/null 用于 virsh 迁移部分,因为我打算无论如何都丢弃输出【参考方案2】:

尝试交换重定向的顺序(到2>&1 >/dev/null)。您当前的代码将 stdout 和 stderr 都发送到 /dev/null (所以我有点好奇为什么会打印 anything)。

为什么这是必要的?语法2>&1 表示“将标准输出(描述符 1)复制为标准错误(描述符 2)”;实际上,stderr 被制作成当前标准输出的副本。如果你把>/dev/null放在前面,那么stdout首先被重定向到/dev/null,然后stderr指向当前的stdout,即/dev/null。

但是如果你把>/dev/null放在第二个,stderr 将首先成为当前stdout(正常输出流)的副本,然后重定向stdout。所以命令的 stderr 打印到 tty(或解释器),就好像它来自 stdout,而 stdout 被静音。这是你想要的行为。

来自man bash

请注意,重定向的顺序很重要。比如命令

ls > dirlist 2>&1

将标准输出和标准错误都指向文件目录列表,而命令

ls 2>&1 > dirlist

仅将标准输出定向到文件 dirlist,因为标准错误被重复 在标准输出被重定向到目录列表之前作为标准输出。

【讨论】:

这些重定向只影响“virsh”命令(使其静音),而不影响“time”命令的输出。 虽然我也很好奇,为什么带有'verbose'标志的命令输出应该被静音:) 啊,你是对的。我误读了命令。看来我的报价匹配技巧需要改进:) 顺便说一句,很好的解释 - 我一直想知道这种行为,你的回答解释了事情。 详细选项是强制 virsh migrate 命令保持进程前台。它不是真的需要,但以防万一某些 virsh 版本可能会将进程发送到后台。

以上是关于在 bash 脚本中将 SSH 输出捕获为变量的主要内容,如果未能解决你的问题,请参考以下文章

如何将curl的输出捕获到bash中的变量[重复]

在文本文件中将纪元转换为标准的bash脚本[重复]

为啥使用 Bash 只读变量捕获输出无法捕获返回码 $?

sh 如何在shell脚本/ bash中将输出附加到文本文件的末尾?

将标准输出捕获到变量,但仍将其显示在控制台中

在 Bash 脚本中将 Telnet 命令传递给 SSH