简体   繁体   English

首先重定向到文件 STDOUT 然后是 STDERR

[英]Redirect to a file STDOUT first and then STDERR

I have a gawk code like this.我有一个像这样的傻瓜代码。

#!/usr/bin/gawk -f

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

I want to redirect to a file tmp, first the stdout and then the stderr.我想重定向到一个文件 tmp,首先是标准输出,然后是标准错误。 I tried this:我试过这个:

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

But this call append to the file first stderr.但是这个调用首先附加到文件 stderr。 I don't want to divide them into two files, so I'm asking if there's a way to do that.我不想将它们分成两个文件,所以我问是否有办法做到这一点。

In ./file there's such a line:在 ./file 中有这样一行:

hello
hello
howareyou
well
well

while in tmp file在 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

The problem you are encountering is due to the buffering of the streams stdout and stderr .您遇到的问题是由于流stdoutstderr的缓冲造成的。 Both streams have different default buffer-settings.两个流都有不同的默认缓冲区设置。 While stdout is line-buffered when writing to a terminal, it is very well buffered when it writes to a stream/pipe/file.虽然stdout在写入终端时是行缓冲的,但在写入流/管道/文件时缓冲得很好。 The stream stderr on the other hand is always unbuffered.另一方面,流stderr总是无缓冲的。 That is why you first encounter the output of stderr and only later the output of stdout in your file tmp .这就是为什么您首先遇到stderr的输出,然后才在文件tmp遇到stdout的输出。 Be aware, however, that the output will be interleaved when you output more lines as all of a sudden the buffer of stdout will be full and written to the file, following again with some output of stderr until the next buffer of stdout is full.但是请注意,当您输出更多行时,输出将被交错,因为突然间stdout的缓冲区将满并写入文件,然后再次输出一些stderr直到stdout的下一个缓冲区已满。 The problem is nicely explained in the following page:下一页很好地解释了这个问题:

One of the ugly hacks you can apply is the usage of stdbuf to change the buffering of the datastreams of awk :您可以应用的丑陋技巧之一是使用stdbuf来更改awk数据流的缓冲:

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

Here we use stdbuf to set buffering mode of the streams stdout and stderr to line-buffering and thus the output of your code would look like:在这里,我们使用stdbuf将流stdoutstderr缓冲模式设置为行缓冲,因此您的代码输出将如下所示:

hello
hello 1
hello
hello 2
...

If you really want first all output of stdout followed by all output of stderr , you should follow the approach mentioned by Ed Morton .如果你真的想要首先所有stdout输出,然后是所有stderr ,你应该遵循Ed Morton提到的方法。

This is a small example:这是一个小例子:

I am not sure what you mean, if I understand it...我不确定你的意思,如果我理解的话......

If you want to redirect stdout to file_out , redirect stderr to file_err , you can do this...如果要将stdout重定向到file_out ,将stderr重定向到file_err ,则可以执行此操作...

command > file_out 2> file_err

There is no good way* to tell awk or the shell that it must buffer stderr until the tool finishes executing.没有好的方法*告诉 awk 或 shell 在工具完成执行之前它必须缓冲 stderr。 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):否则,您可以自己缓冲 stderr 并在最后打印(但这仅适用于您手动打印的 stderr 消息,而不适用于 gawk 自己生成的消息):

{
    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.当然,如果这就是你所做的一切,你实际上根本不需要使用 stderr,只需打印到 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. *如果行星以某种方式排列和/或您有某些工具或某种外壳,您可以使用一些奥术咒语来实现这一点,但只要保持简单,如上所示。

Lit bit old, but if someone still needs it:有点旧,但如果有人仍然需要它:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM