如何将stdout重定向到文件,以及stdout + stderr重定向到另一个文件?


32

我该如何实现

cmd >> file1 2>&1 1>>file2

也就是说,stdout stderr应该重定向到一个文件(file1),而只有stdout(file2)应该重定向到另一个文件(都处于追加模式)?

Answers:


41

问题是,当您重定向输出时,它不再可用于下一个重定向。您可以通过管道传递到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)


16

zsh

cmd >& out+err.log > out.log

在追加模式下:

cmd >>& out+err.log >> out.log

在中zsh,并且在mult_ios未禁用该选项的情况下,当多次重定向文件描述符(此处为1)以进行写入时,Shell将实现内置功能tee以将输出复制到所有目标。


我想不出有什么out+errout意味着在这里。文件名?要重定向的流?
gronostaj

@gronostaj认为命令显示为cmd >& file1 > file2
Isaac

此解决方案将保留生成输出的顺序。要实际存储stdout和stderr(按该顺序),您需要使用其他方法。
以撒

1
@Isaac,顺序不一定会被保留,因为stdout输出将通过管道(到达将其转发到每个文件的进程),而stderr输出将直接进入文件。无论如何,看起来OP都不要求stderr输出在stdout输出之后。
斯特凡Chazelas

3

您可以:标记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

这真的很难理解。(1)为什么使用如此复杂的用例(ls unknown)在stderr上打印内容? >&2 echo "error"会没事的。(2)tee可以一次附加到多个文件。(3)为什么不只是cat代替grep "^"?(4)当stderr输出以开头时,脚本将失败_stdout_。(5)为什么?
pLumo

@RoVo:前两行注释显示了算法,比概念验证示例更简单。1):这ls loop将同时在stdout和stderr上以受控顺序混合输出(或者),以便我们可以检查是否保留了stderr / stdout的顺序,尽管对stdout进行了标记2):gnu tail,也许,但不是普通尾巴(例如,在aix上)。3):grep“ ^”也显示两个文件名。4):可以通过变量更改。5):复杂的示例适用于我测试过的旧ose(例如,旧aix)(没有perl)。
奥利维尔·杜拉克

(1)对stderr和stout的多次回波会很好,但是好吧,不重要,只会更容易阅读。(3)同意,(4)可以肯定,但是如果以变量包含的任何内容开头,它将失败。(5)我明白了。
pLumo

@RoVo我同意你的观点1)。对于4),变量可以根据需要变得复杂以使pb消失(例如:uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406...)
Olivier Dulac

1
当然,这不太可能,但是无论如何它可能会在以后引入安全问题。然后您可能想要在打印到文件之前删除该字符串;-)
pLumo

2

如果输出顺序必须为: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

要提供teestdout(要重复的代码),我们需要直接从命令中使用stderr。一种方法,如果顺序不重要(输出的顺序(很可能)将保留为生成的顺序,则先输出的先输出)。要么:

  1. cmd 2>>file1 | tee -a file2 >>file1
  2. cmd 2>>file1 > >( tee -a file2 >>file1 )
  3. ( cmd | tee -a file2 ) >> file1 2>&1

选项2仅在某些shell中有效。选项3使用附加的子Shell(速度较慢),但仅使用文件名一次。

但是,如果必须首先输出stdout (无论生成了哪个顺序的输出),我们都需要存储stderr以将其附加到文件的末尾(发布第一个解决方案)。


1
或存储在内存一样sponge的作用:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
斯特凡Chazelas

1

为了多样性:

如果您的系统支持/dev/stderr,则

(cmd | tee -a /dev/stderr) 2>> file1 >> file2

将工作。的标准输出cmd 发送到管道的stdout和stderr。的标准误差cmd绕过绕过tee 管道的标准错误。

所以

  • 管道的标准输出只是 cmd,并且
  • 管道的stderr是stdout和stderr cmd混合在一起。

然后,将这些流发送到正确的文件就很简单了。

与几乎任何类似这样的方法(包括Stéphane的答案)一样, file1可能会使行混乱。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.