将printf重定向到awk中的文件

Yan*_*321 6 linux bash awk

我有一个简单的bash脚本.

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

  stdbuf -o0 tail -f test.log | awk -F'[ "]+' '{
  ipcount[$1]++;
  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] }
}'
Run Code Online (Sandbox Code Playgroud)

主要逻辑是有效的.我唯一的问题是重定向到"out.log"似乎不起作用.最后一个printf将预期结果输出到标准输出.但另外两个printf没有输出任何东西到"out.log",我无法弄清楚为什么.out.log拥有所有权限(777)

Mr.*_*ama 9

这应该适合你:

tail -f test.log | awk -F'[ "]+' -v out_file="out.log" '{
    val_count[$1]++
    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)
}'
Run Code Online (Sandbox Code Playgroud)

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

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

要解决这个问题,我们需要close在每次迭代后使用该文件.这有力地将输出刷新到out.log并强制>重定向在下一次迭代时重新截断文件.如果您不需要截断每次迭代,那么简单fflush(out_file)就足够了.


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

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

ls -l | awk '{ print "This file has many lines" > "output.txt"; }'
Run Code Online (Sandbox Code Playgroud)

这导致output.txt使用单个输出行,因为它被多次截断:

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

  • @ Yan4321-嗯,另一个障碍是awk喜欢缓冲输出(除非输出将输出到终端)。要解决此问题,您需要“清空”文件或流。 (2认同)