#basic principle (some un-necessary "{}" to visually help see the layers):
# { { complex command ;} | sed -e "s/^/TAGstdout/" ;} 2>&1 | read_stdin_and_redispatch
#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
# to see if the order of stdout&stderr is kept
#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
\rm out.file out_AND_err.file unknown unknown2
touch existing existing2 existing3
#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs...
# avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.
{
{ for f in existing unknown existing2 unknown2 existing3 ; do ls -l "$f" ; sleep 1; done ;
} | sed -u -e "s/^/${uniquetag}/" ;
} 2>&1 | while IFS="" read -r line ; do
case "$line" in
${uniquetag}*) printf "%s\n" "$line" | tee -a out_AND_err.file | sed -e "s/^${uniquetag}//" >> out.file ;;
*) printf "%s\n" "$line" >> out_AND_err.file ;;
esac;
done;
# see the results:
grep "^" out.file out_AND_err.file
问题是,当您重定向输出时,它不再可用于下一次重定向。您可以通过管道传递到
tee
子shell 以保留第二次重定向的输出:或者如果您想在终端中查看输出:
为避免将第一个的 stderr 添加
tee
到file1
,您应该将命令的 stderr 重定向到某个文件描述符(例如 3),然后再次将其添加到 stdout:(感谢@fra-san)
与
zsh
:在附加模式下:
在
zsh
, 并且如果该mult_ios
选项未被禁用,当文件描述符(此处为 1)被重定向多次以进行写入时,shell 会实现一个内置函数tee
以将输出复制到所有目标。您可以:标记标准输出(使用 UNBUFFERED sed,即:)
sed -u ...
,让标准错误也转到标准输出(未标记,因为它没有通过标记 sed),因此能够区分结果日志文件中的 2。以下: 很慢(它可以被严重优化,例如使用 perl 脚本而不是 while ... ; do ... ; 完成,例如,每行都会产生子shell和命令!),很奇怪(似乎我需要 2 个 {} 阶段来重命名 stdout,然后在另一个中添加“失败”的 stderr)等等。但它是:一个“概念证明”,它将尝试保持输出的顺序尽可能多的 stdout 和 stderr :
如果输出顺序必须是:stdout 然后 stderr ; 仅重定向没有解决方案。
标准错误必须存储到临时文件中
描述:
将一个输出(像 stdout 或 stderr 这样的 fd)重定向到两个文件的唯一方法是重现它。该命令
tee
是重现文件描述符内容的正确工具。因此,在两个文件上具有一个输出的最初想法是使用:这会将 tee 的标准输入复制到两个文件(1 和 2)中,而 tee 的输出仍未使用。但是我们需要附加(使用
-a
)并且只需要一份。这解决了两个问题:要提供
tee
标准输出(要重复的那个),我们需要直接从命令中使用标准错误。一种方法,如果顺序不重要(输出顺序(很可能)将保留为生成的,无论哪个先输出,都将首先存储)。任何一个:cmd 2>>file1 | tee -a file2 >>file1
cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
选项 2 仅适用于某些 shell。选项 3 使用额外的子外壳(较慢),但仅使用文件名一次。
但是如果stdout 必须是第一个(无论生成哪个顺序输出),我们需要存储 stderr 以将其附加到最后的文件中(发布的第一个解决方案)。
为了多样性:
如果你的系统支持
/dev/stderr
,那么将工作。的标准输出
cmd
被发送到管道的标准输出和标准错误。标准错误cmd
绕过tee
并从管道的标准错误中出来。所以
cmd
输出cmd
混合的标准输出和标准错误。然后将这些流发送到正确的文件就很简单了。
与几乎任何这样的方法(包括Stéphane's answer)一样,
file1
可能会使线路混乱。