我试图编写一个脚本,基本上充当一个由非交互式命令创建的所有输出的传递日志,而不影响命令对其他进程的输出。也就是说,标准输出和标准错误应该与没有经过我的命令运行时一样。
为了做到这一点,我尝试将标准输出和标准错误分别重定向到两个不同的Tee中,每个Tee都用于不同的文件,然后重新组合它们,以便它们仍然出现在标准输出和标准错误上。我看到很多关于Tee和重定向的其他问题,并尝试了一些从中获得的答案,但没有一个似乎能够正确地将流分离到单独的Tee中并重新组合它们。
我的尝试成功地将输出拆分到正确的文件中,但是流不能正确地保留实际的标准输出/标准错误输出。我在更复杂的设置中看到了这一点,所以我创建了简化的命令,其中我将数据回显到标准输出或标准错误作为我的“命令”,如下所示。
这里有一些我尝试过的事情:
{ command | tee ~/tee.txt; } 2>&1 | { tee ~/tee2.txt 1>&2; }
运行我的简单测试,我看到:
$ { { { echo "test" 1>&2; } | tee ~/tee.txt; } 2>&1 | { tee ~/tee2.txt 1>&2; } } > /dev/null
test
$ { { { echo "test" 1>&2; } | tee ~/tee.txt; } 2>&1 | { tee ~/tee2.txt 1>&2; } } 2> /dev/null
$
好的,这正是我所期望的。我将输出到stderr,因此当我将最终的stderr重定向到/dev/null时,我希望看不到任何内容,而当我仅重定向stdout时,我希望看到我的原始输出。
$ { { { echo "test"; } | tee ~/tee.txt; } 2>&1 | { tee ~/tee2.txt 1>&2; } } > /dev/null
test
$ { { { echo "test"; } | tee ~/tee.txt; } 2>&1 | { tee ~/tee2.txt 1>&2; } } 2> /dev/null
$
这是反过来的!我的命令只将数据发送到stdout,因此当我将最终的stdout重定向到null时,我希望看不到任何东西。但相反的情况发生了。
这是我尝试的第二个命令,它有点更复杂:
{ command 2>&3 | tee ~/tee.txt; } 3>&1 1>&2 | { tee /home/michael/tee2.txt 1>&2; }
很遗憾,我看到了与以前完全相同的行为。
我不太清楚自己做错了什么,但似乎stdout出现了某些问题。对于第一条命令,我怀疑是因为在把stdout和stderr (2>&1
) 组合后再将其流到第二个tee时发生了冲突,但如果是这种情况,我希望在tee2.txt文件中看到stdout和stderr两个输出,但实际上只有stderr!对于第二条命令,我根据我所读到的答案得出的印象是,为避免这个问题,描述符正在被交换,但显然还是出了问题。
编辑:我又想到了一个可能性,即第二个命令失败是因为我正在重定向1>&2
,这会杀死第一个tee的stdout。所以我尝试使用1>&4
进行重定向,然后在最后将其重定向回stdout:
{ command 2>&3 | tee ~/tee.txt; } 3>&1 1>&4 | { tee /home/michael/tee2.txt 1>&2 4>&1; }
但现在我明白了:
-bash: 4: Bad file descriptor
最后我也尝试将描述符2重定向回到描述符1中:
{ command 2>&3 | tee ~/tee.txt; } 3>&1 1>&2 | { tee /home/michael/tee2.txt 1>&2 2>&1; }
和:
{ command 2>&3 | tee ~/tee.txt; } 3>&1 1>&2 | { tee /home/michael/tee2.txt 1>&2; } 2>&1
stderr
和stdout
分开,而是将它们合并了。例如,如果我在整个语句中包装{ ... } > /dev/null
,我看不到任何输出,但如果我将其包装在{ ... } 2> /dev/null
中,我会看到 "stdout" 和 "stderr"。 - Michael(tee stderr.txt 1&2)
看起来达到了预期的效果。 - Michael2> >(tee stderr 1>&2)
,是的,我忘记将tee
的输出恢复到标准错误了。 - chepner