如何将命令输出存储到变量中并同时打印输出?

31

假设我想要在屏幕上输出一些内容并将其保存到一个变量中,同时我也想在屏幕上看到它。

echo "hello" | tee tmp_file
var=$(< tmp_file)

现在我可以在终端中看到hello,并将其保存到变量$var中。

但是,有没有不使用临时文件的方法来实现这一点?tee似乎不是解决方案,因为它说(来自man tee从标准输入读取并写入标准输出和文件,而这里是两次标准输出。

我在Bash 4.3中,如果这很重要。


@xhienne,实际上这个问题更清晰,那个问题有很好的答案,但也有一些无用的噪音。 - oguz ismail
@oguzismail 不,那些答案最多是误导。当需要写到 stdout 时,不应该写入 /dev/tty/dev/tty 可能根本不存在。 - xhienne
@oguzismail 这正是为什么另一个答案更好的原因。在这里,你必须挖掘到最少赞的答案才能找到正确的东西。那里,被接受的答案是正确的,如果你的bash太旧而无法提供命令替换,则第二和第三个答案将解决问题。 - xhienne
@oguzismail 我认为这是一种非常有用的方法,每个人都会从中受益。如果这是我的帖子之一,我将非常乐意接受它。 - fedorqui
@xhienne 我想说的是网站的基本原则:改进帖子,使它们对下一个看到它们的人有用。我不够专业,无法确定 你所说的 是否适用于所有情况。因此,我认为最好有一个更新的答案来解释其缺点和替代选项。这种方法只在这里出现。我不介意重复是这个还是另一个,我分享你的目标,希望拥有优质内容。 - fedorqui
显示剩余6条评论
4个回答

45

使用 tee 命令将内容直接输出到屏幕而不是标准输出流(stdout)

$ var=$(echo hi | tee /dev/tty)
hi
$ echo $var
hi

5
这个方法可行,完全符合提问者的要求。请注意,如果调用脚本的程序正在读取标准输出流stdout,他们将无法看到您发送到/dev/tty的内容(这应该是显而易见的,但这也让我感到困惑,所以我想分享一下)。 - MatrixManAtYrService
这肯定会破坏行间距。 - vladkras
2
@vladkras 不会,如果你想保留空格/特殊字符,请引用变量。 - 123
1
@123 你刚刚帮我省了半个小时的调试时间... - SO_fix_the_vote_sorting_bug

10

管道命令 tee 就是关键。

这是我在这个问题中讨论的方法。

var=$(echo "hello" | tee /dev/tty)
< p >那么您可以使用< code > $var 来获取存储的变量。

< p >例如:

var=$(echo "hello" | tee /dev/tty); echo "$var world"

将输出:

hello
hello world

您可以通过管道做更多的事情,例如我想在终端中打印一个短语,并同时告诉它中有多少个“l”:

count=$(echo "hello world" | tee /dev/tty | grep -o "l" | wc -l); echo "$count"

这会打印出:

hello world
3

这与我的答案有何不同? - 123
截至这个问题,还没有。但是我有另一个要求比这个稍微复杂一些,在我上面提到的问题中,我自己解决了。所以 OP 邀请我也在这里发布。就这样。 - Leo
谢谢您也发布了答案!一切发生得如此之快:您在另一个问题中回复,我在这里提问,@123发布了他的答案。现在我们把所有信息都放在同一个地方,更容易找到。感谢大家! - fedorqui

6

非常好,因为它不依赖于proc文件系统上的特定文件名(即在MacOS上也可以工作)。exec 10>&1 在zsh上失败(并关闭shell,因为它将10解释为用来替换shell的命令(然后失败,因为10不是有效的命令),但将10替换为9,一切都正常 :):exec 9>&1 - Claude

5
将其发送到标准错误输出。
var="$(echo "hello" | tee /dev/stderr)"

或者将stdout复制到更高的FD并将其发送到那里。

$ exec 10>&1
$ var="$(echo "hello" | tee /proc/self/fd/10)"
hello
$ echo "$var"
hello

呃,非常有趣。您能详细说明一下FD这部分吗?对我来说,“exec 10>&1”听起来很奇怪。 - fedorqui
2
@fedorqui:在bash中,exec有两个作用。第一个是用新进程替换当前进程。第二个是使用重定向语法操作文件描述符。如果没有指定命令,则FD重定向将应用于当前进程。 - Ignacio Vazquez-Abrams
1
@fedorqui &1 指向 /proc/self/fd/1,该文件指向 /dev/pts/1,即终端屏幕。这意味着 /proc/self/fd/10 指向与 /proc/self/fd/1 相同的文件,即终端屏幕。这意味着当使用 tee 命令时,它会直接输出到终端,而 stdout(&1) 则被赋值所捕获。这是一种迂回的方式,只是为了将输出重定向到 /dev/pts/1 - 123

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接