重定向到文件STDOUT firts,然后STDERR

时间:2019-06-01 10:48:40

标签: bash redirect awk stdout stderr

我有这样的通用代码。

#!/usr/bin/gawk -f

1 {
    for (i=0;i<5;i++){
        print $0
        print $0, 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

4 个答案:

答案 0 :(得分:1)

这是一个小例子:

我不确定您的意思,如果我理解的话...

如果要将stdout重定向到file_out,将stderr重定向到file_err,则可以执行此操作...

command > file_out 2> file_err

答案 1 :(得分:1)

There is no good way* to tell awk or the shell that it must buffer stderr until the tool finishes executing. Keep it simple and just do this:

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

Otherwise you could buffer stderr yourself and print at the end (but this will only work for stderr messages you are manually printing, not messages gawk is generating itself):

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

and then call as:

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

Of course you don't actually need to use stderr at all if that's all you're doing with it, just print to stdout.

*There may be some arcane incantation you can use to make this happen if the planets align a certain way and/or you have certain tools or a certain shell but just keep it simple as shown above.

答案 2 :(得分:1)

您遇到的问题是由于流stdoutstderr的缓冲。这两个流具有不同的默认缓冲区设置。尽管stdout在写入终端时是行缓冲的,但在写入流/管道/文件时,缓冲得很好。另一方面,流stderr始终未被缓冲的。这就是为什么您首先在文件stderr中遇到stdout的输出,然后才遇到tmp的输出的原因。但是请注意,当您输出更多行时,输出将被交错,因为突然stdout的缓冲区将被填满并写入文件,然后再次输出stderr,直到stdout的下一个缓冲区已满。在下一页中很好地解释了该问题:

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

$ stdbuf -oL -eL awk '{...}' file.txt &> tmp.txt

在这里,我们使用stdbuf将流stdoutstderr的缓冲模式设置为行缓冲,因此代码的输出将类似于:

hello
hello 1
hello
hello 2
...

如果您确实要先输出stdout的所有 all ,然后才是stderr的所有输出,则应遵循Ed Morton所述的方法。

答案 3 :(得分:0)

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

echo "some stuff" | awk '{
    for (i=0;i<5;i++){
        print $0;
        # print i on stderr
        system(">&2 echo " i);
    }
}'
相关问题