当前位置: 首页>>技术教程>>正文


将stdout捕获到变量,但仍将其显示在控制台中

, , ,

问题描述

我有一个bash脚本,它调用了几个long-running进程。由于处理原因,我想将这些调用的输出捕获到变量中。但是,由于这些进程是长时间运行的进程,因此我希望rsync调用的输出在real-time的控制台中显示,而不要在此之后显示。

为此,我有found的一种实现方法,但它依赖于将文本输出到/dev /stderr。我觉得输出到/dev /stderr并不是一个好方法。

VAR1=$(for i in {1..5}; do sleep 1; echo $i; done | tee /dev/stderr)

VAR2=$(rsync -r -t --out-format='%n%L' --delete -s /path/source1/ /path/target1 | tee /dev/stderr)

VAR3=$(rsync -r -t --out-format='%n%L' --delete -s /path/source2/ /path/target2 | tee /dev/stderr)

在上面的示例中,我多次调用rsync,并且希望在处理文件时看到它们的名称,但是最后我仍然希望将输出结果包含在变量中,因为稍后将对其进行解析。

有’cleaner’方式可以做到这一点吗?

如果有所作为,我正在使用Ubuntu 12.04,bash 4.2.24。

最佳解决方法

在您的shell中复制& 1(在我的示例中为5),在子shell中使用& 5(这样您将写入父shell的stdout(& 1)):

exec 5>&1
FF=$(echo aaa|tee >(cat - >&5))
echo $FF

将打印aaa两次,一次是由于子 shell 中的回显,而第二次将打印变量的值。

在您的代码中:

exec 5>&1
VAR1=$(for i in {1..5}; do sleep 1; echo $i; done | tee >(cat - >&5))
# use the value of VAR1

次佳解决方法

Op De Cirkel的答案具有正确的想法。它甚至可以进一步简化(避免使用cat):

exec 5>&1
FF=$(echo aaa|tee /dev/fd/5)
echo $FF

第三种解决方法

这是捕获stderr和命令的退出代码的示例。这是基于罗素·戴维斯(Russell Davis)的答案。

exec 5>&1
FF=$(ls /taco/ 2>&1 |tee /dev/fd/5; exit ${PIPESTATUS[0]})
exit_code=$?
echo "$FF"
echo "Exit Code: $exit_code"

如果文件夹/taco/存在,它将捕获其内容。如果该文件夹不存在,它将捕获一条错误消息,并且退出代码为2。

如果您省略2>&1,则仅stdout将被捕获。

第四种方法

您可以使用三个以上的文件描述符。试试这里:

http://tldp.org/LDP/abs/html/io-redirection.html

“每个打开的文件都分配有一个文件描述符。[2] stdin,stdout和stderr的文件描述符分别为0、1和2。要打开其他文件,则保留描述符3到9。将这些其他文件描述符之一分配给stdin,stdout或stderr作为临时重复链接。”

关键是仅仅为了实现此结果而使脚本更复杂是否值得。实际上,这并不是真的错误,您的操作方式。

第五种方法

如果通过”the console”表示您当前的TTY,请尝试

variable=$(command with options | tee /dev/tty)

这是一种有点可疑的做法,因为尝试使用此方法的人有时会在没有TTY的情况下(临时工作等)将输出降到意外的地方时感到惊讶。

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/7394.html,未经允许,请勿转载。