23

在编写 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'")

响应的值只是空的,尽管时间被打印到标准输出。

4

2 回答 2

44

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

您应该将 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)
于 2012-08-21T05:39:16.533 回答
2

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

为什么这是必要的?语法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

将标准输出和标准错误都指向文件 dirlist,而命令

ls 2>&1 > dirlist

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

于 2012-08-21T05:37:45.680 回答