我该如何实现
cmd >> file1 2>&1 1>>file2
也就是说,stdout 和 stderr应该重定向到一个文件(file1),而只有stdout(file2)应该重定向到另一个文件(都处于追加模式)?
我该如何实现
cmd >> file1 2>&1 1>>file2
也就是说,stdout 和 stderr应该重定向到一个文件(file1),而只有stdout(file2)应该重定向到另一个文件(都处于追加模式)?
Answers:
问题是,当您重定向输出时,它不再可用于下一个重定向。您可以通过管道传递到tee
子外壳中,以保留第二次重定向的输出:
( cmd | tee -a file2 ) >> file1 2>&1
或者如果您想在终端中查看输出:
( cmd | tee -a file2 ) 2>&1 | tee -a file1
为了避免将第一个的stderr添加tee
到中file1
,您应该将命令的stderr重定向到某个文件描述符(例如3),然后再将其添加到stdout中:
( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1
(感谢@ fra-san)
与zsh
:
cmd >& out+err.log > out.log
在追加模式下:
cmd >>& out+err.log >> out.log
在中zsh
,并且在mult_ios
未禁用该选项的情况下,当多次重定向文件描述符(此处为1)以进行写入时,Shell将实现内置功能tee
以将输出复制到所有目标。
cmd >& file1 > file2
您可以:标记stdout(使用UNBUFFERED sed,即:)sed -u ...
,让stderr也转到stdout(未标记,因为它没有通过该标记sed),因此能够在结果日志文件中区分2。
以下是:很慢(可以通过使用perl脚本而不是while ...; do ...; done,例如,可以在每一行产生子shell和命令来进行认真优化),很奇怪(似乎我需要2个{}阶段,在一个重命名标准输出中,然后在另一个阶段中添加“掉线”标准错误),等等。但这是:“ 概念证明 ”,它将尝试保持输出的顺序应尽可能多地使用stdout和stderr:
#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
ls unknown
)在stderr上打印内容? >&2 echo "error"
会没事的。(2)tee
可以一次附加到多个文件。(3)为什么不只是cat
代替grep "^"
?(4)当stderr输出以开头时,脚本将失败_stdout_
。(5)为什么?
ls loop
将同时在stdout和stderr上以受控顺序混合输出(或者),以便我们可以检查是否保留了stderr / stdout的顺序,尽管对stdout进行了标记2):gnu tail,也许,但不是普通尾巴(例如,在aix上)。3):grep“ ^”也显示两个文件名。4):可以通过变量更改。5):复杂的示例适用于我测试过的旧ose(例如,旧aix)(没有perl)。
uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406
...)
如果输出顺序必须为:stdout然后stderr;仅重定向没有解决方案。
stderr必须存储到临时文件
cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err
描述:
将一个输出(如stdout或stderr之类的fd)重定向到两个文件的唯一方法是重现它。该命令tee
是再现文件描述符内容的正确工具。因此,最初的想法是在两个文件上有一个输出:
... | tee file1 file2
这会将tee的stdin复制到两个文件(1&2),而tee的输出仍未使用。但是我们需要追加(使用-a
),并且只需要一个副本。这解决了两个问题:
... | tee -a file1 >>file2
要提供tee
stdout(要重复的代码),我们需要直接从命令中使用stderr。一种方法,如果顺序不重要(输出的顺序(很可能)将保留为生成的顺序,则先输出的先输出)。要么:
cmd 2>>file1 | tee -a file2 >>file1
cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
选项2仅在某些shell中有效。选项3使用附加的子Shell(速度较慢),但仅使用文件名一次。
但是,如果必须首先输出stdout (无论生成了哪个顺序的输出),我们都需要存储stderr以将其附加到文件的末尾(发布第一个解决方案)。
sponge
的作用:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
为了多样性:
如果您的系统支持/dev/stderr
,则
(cmd | tee -a /dev/stderr) 2>> file1 >> file2
将工作。的标准输出cmd
发送到管道的stdout和stderr。的标准误差cmd
绕过绕过tee
管道的标准错误。
所以
cmd
,并且cmd
混合在一起。然后,将这些流发送到正确的文件就很简单了。
与几乎任何类似这样的方法(包括Stéphane的答案)一样,
file1
可能会使行混乱。
out+err
和out
意味着在这里。文件名?要重定向的流?