先重定向到文件 STDOUT,然后再重定向到 STDERR

Redirect to a file STDOUT first and then STDERR

我有这样的 gawk 代码。

#!/usr/bin/gawk -f

1 {
    for (i=0;i<5;i++){
        print [=10=]
        print [=10=], i > "/dev/stderr"
    }
}

我想重定向到文件 tmp,首先是 stdout,然后是 stderr。我试过这个:

gawk -f Documents/gawk_script.awk ./file &> tmp

但是这个调用首先附加到文件 stderr。我不想把它们分成两个文件,所以我想问一下是否有办法做到这一点。

在./file中有这样一行:

hello
hello
howareyou
well
well

在 tmp 文件中

hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
howareyou
howareyou
howareyou
howareyou
howareyou
well
well
well
well
well
well
well
well
well
well
well
hello 0
hello 1
hello 2
hello 3
hello 4 
hello 0
hello 1
hello 2
hello 3
hello 4
howareyou 0
howareyou 1
howareyou 2
howareyou 3
howareyou 4
well 0
well 1
well 2
well 3
well 4
well 0
well 1
well 2
well 3
well 4

这是一个小例子:

我不太明白你的意思,如果我明白了...

如果你想将 stdout 重定向到 file_out ,将 stderr 重定向到 file_err ,你可以这样做...

command > file_out 2> file_err

没有好的方法*告诉 awk 或 shell 它必须缓冲 stderr 直到工具完成执行。保持简单,只需这样做:

awk -f script.awk file > out 2>tmp; cat tmp >> out && rm -f tmp

否则你可以自己缓冲 stderr 并在最后打印(但这只适用于你手动打印的 stderr 消息,而不是 gawk 自己生成的消息):

{
    for (i=0;i<5;i++){
        print [=11=]
        errs = errs [=11=] OFS i ORS
    }
}
END {
    printf "%s", errs > "/dev/stderr"
}

然后调用为:

awk -f script.awk file > out 2>&1

当然,如果您只使用它,您实际上根本不需要使用 stderr,只需打印到 stdout。

*如果行星以某种方式对齐,您可能会使用一些神秘的咒语来实现这一点 and/or 您有某些工具或某种 shell 但请保持简单,如图所示以上。

您遇到的问题是由于流 stdoutstderr 的缓冲造成的。两个流都有不同的默认值 buffer-settings。虽然 stdout 在写入终端时是 line-buffered,但在写入 stream/pipe/file 时缓冲得很好。另一方面,流 stderr 总是 无缓冲。这就是为什么您首先遇到 stderr 的输出,然后才在文件 tmp 中遇到 stdout 的输出。但是请注意,当您输出更多行时,输出将交错,因为突然之间 stdout 的缓冲区将满并写入文件,然后再次输出 stderr 直到stdout 的下一个缓冲区已满。下一页很好地解释了这个问题:

您可以应用的丑陋技巧之一是使用 stdbuf 来更改 awk:

的数据流缓冲
$ stdbuf -oL -eL awk '{...}' file.txt &> tmp.txt

此处我们使用 stdbuf 将流 stdoutstderr 的缓冲模式设置为 line-buffering,因此您的代码输出如下所示:

hello
hello 1
hello
hello 2
...

如果你真的想要先 all 输出 stdout 然后是 stderr 的所有输出,你应该遵循 [=30= 提到的方法].

有点旧,但如果有人还需要它:

echo "some stuff" | awk '{
    for (i=0;i<5;i++){
        print [=10=];
        # print i on stderr
        system(">&2 echo " i);
    }
}'