bash 将 printf 重定向到 awk 中的文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31861398/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 13:24:21  来源:igfitidea点击:

Redirecting printf to file in awk

linuxbashawk

提问by Yan4321

I have a simple bash script.

我有一个简单的 bash 脚本。

It's purpose is to monitor http access log file (test.log) and output to a file (out.log) the updated hit rate:

它的目的是监视 http 访问日志文件 (test.log) 并将更新的命中率输出到文件 (out.log):

  stdbuf -o0 tail -f test.log | awk -F'[ "]+' '{
  ipcount[]++;
  print "test" > "out.log"; #Truncate out.log
  for (i in ipcount) {
        printf "%15s - %d\n", i, ipcount[i] >> "out.log";
        printf "%15s - %d\n", i, ipcount[i] }
}'

The main logic works. my only problem is the redirection to "out.log" that doesn't seem to work. The last printf outputs the expected result to the standard output. But the other two printf do not output anything to "out.log", and I cannot figure out why. out.log has all permissions (777)

主要逻辑有效。我唯一的问题是重定向到“out.log”似乎不起作用。最后一个 printf 将预期结果输出到标准输出。但是另外两个 printf 没有向“out.log”输出任何内容,我不知道为什么。out.log 拥有所有权限 (777)

回答by Mr. Llama

This should work for you:

这应该适合你:

tail -f test.log | awk -F'[ "]+' -v out_file="out.log" '{
    val_count[]++
    print "" > out_file

    for (i in val_count) {
        printf "%15s - %d\n", i, val_count[i] >> out_file
        printf "%15s - %d\n", i, val_count[i]
    }

    close(out_file)
}'

(Note: I moved the output file definition to the command line to hopefully reduce repetition.)

(注意:我将输出文件定义移到命令行以希望减少重复。)

Your original version has one fatal issue: print "" > "out.log"only truncates out.logthe firsttime it's called. All subsequent calls to it will simply append to it because it's already open. As a secondary issue, awk likes to buffer output, so the contents will only be flushed intermittently.

您的原始版本有一个致命问题:print "" > "out.log"out.log一次调用时截断。对它的所有后续调用都将简单地附加到它,因为它已经打开了。作为次要问题,awk 喜欢缓冲输出,因此内容只会间歇性地刷新。

To fix this, we need to closethe file after each iteration. This forcefully flushes the output to out.logand forces the >redirection to re-truncate the file on the next iteration. If you didn't need to truncate each iteration, a simple fflush(out_file)would suffice.

为了解决这个问题,我们需要close在每次迭代后修改文件。这会强制将输出刷新到out.log并强制>重定向在下一次迭代中重新截断文件。如果您不需要截断每次迭代,一个简单的fflush(out_file)就足够了。



To illustrate the issue more clearly...

为了更清楚地说明问题......

This results in an output.txtthat has multiplelines because it is truncated just once (the first iteration):

这导致output.txt具有行的 ,因为它只被截断一次(第一次迭代):

ls -l | awk '{ print "This file has many lines" > "output.txt"; }'

This results in an output.txtwith a singleoutput line because it is truncated multiple times:

这导致output.txt输出线,因为它被截断多次:

ls -l | awk '{ print "This file has one line" > "output.txt"; close("output.txt"); }'