tail -f |找到数据后,awk和end tail

时间:2013-12-10 17:03:56

标签: awk pipe tail

我正在尝试构建一个脚本tail -f | awk每秒更新一次的日志文件。 awk部分将根据我的搜索参数仅获取日志文件的必需部分。输出XML也在输出文件中捕获。脚本工作正常 - 正如预期的那样。

问题 - 但是,在执行搜索后,由于tail -f,它仍然处于挂起状态。任何想法如何更新下面的脚本 - 这样一旦捕获输出XML,它应该打破尾部??

XMLF=/appl/logs/abc.log

aa_pam=${1-xml}
[[ ${2-xml} = "xml" ]] && tof=xml_$(date +%Y%m%d%H%M%S).xml || tof=$2
tail -f $XMLF | \
awk  ' BEGIN { Print_SW=0; Cnt_line=1; i=0}
       /\<\?xml version\=/ { if (Print_SW==1) p_out(Cnt_Line,i)
                             Print_SW=0; Cnt_line=1;
       }
       { Trap_arry[Cnt_line++]=$0;
       }
       /'${1-xml}'/ { Print_SW=1;
       }
       /\<\/XYZ_999/    { if (Print_SW==1) p_out(Cnt_Line, i);
                             Print_SW=0; Cnt_line=1; }
       END { if (Print_SW==1) p_out(Cnt_Line, i); }
function p_out(Cnt_Line, i) {
       for (i=1;i<Cnt_line;i++) {print Trap_arry[i] | "tee '$tof'" }
}
' | tee $tof

更新 按照以下使用exit的建议进行尝试 - 它成功存在脚本 - 但是在输出中捕获的xml正在重复。所以在输出文件中 - 相同的XML出现两次.. !!

XMLF=/appl/logs/abc.log

aa_pam=${1-xml}
[[ ${2-xml} = "xml" ]] && tof=xml_$(date +%Y%m%d%H%M%S).xml || tof=$2
tail -f $XMLF | \
awk  ' BEGIN { Print_SW=0; Cnt_line=1; i=0}
       /\<\?xml version\=/ { if (Print_SW==1) p_out(Cnt_Line,i)
                             Print_SW=0; Cnt_line=1;
       }
       { Trap_arry[Cnt_line++]=$0;
       }
       /'${1-xml}'/ { Print_SW=1;
       }
       /\<\/XYZ_999/    { if (Print_SW==1) p_out(Cnt_Line, i);
                             Print_SW=0; Cnt_line=1; }
       END { if (Print_SW==1) p_out(Cnt_Line, i); }
function p_out(Cnt_Line, i) {
       for (i=1;i<Cnt_line;i++) {print Trap_arry[i] | "tee '$tof'" } { exit }
}
' | tee $tof

3 个答案:

答案 0 :(得分:2)

在完成捕获输出后,调用exit(在终止前将跳转到END块)。

当awk终止时,write()下一个tail -f到标准输出会导致EPIPE错误。 tail知道在发生这种情况时终止。

更新:您似乎在尝试决定退出的位置时遇到了一些问题。它不应该在p_out中,因为您从p_out块的结束XML标记匹配表达式中调用END。试试这个:

XMLF=/appl/logs/abc.log

aa_pam=${1-xml}
[[ ${2-xml} = "xml" ]] && tof=xml_$(date +%Y%m%d%H%M%S).xml || tof=$2
tail -f $XMLF | \
awk  '
  BEGIN {
    Print_SW=0
    Cnt_line=1
    i=0
  }

  /\<\?xml version\=/ {
     if (Print_SW==1)
        p_out(Cnt_Line,i)
     Print_SW=0
     Cnt_line=1
  }

  {
    Trap_arry[Cnt_line++]=$0
  }

  /'${1-xml}'/ {
    Print_SW=1;
  }

  /\<\/XYZ_999/ {
    if (Print_SW==1)
      p_out(Cnt_Line, i)
    Print_SW=0
    Cnt_line=1
    exit
  }

  END {
    if (Print_SW==1)
      p_out(Cnt_Line, i);
  }

  function p_out(Cnt_Line, i) {
    for (i=1;i<Cnt_line;i++) {
      print Trap_arry[i] | "tee '$tof'"
    }
  }
' | tee $tof

答案 1 :(得分:1)

您可以在awk脚本中添加一行,例如:

/some-end-of-xml-marker/  {  close(/dev/stdin) ; }

我没有尝试过,但是你明白了:当你到达文件的末尾时关闭STDIN,这样awk中的循环停止,你到达END部分(未经测试,我希望这证明了是正确的......)

答案 2 :(得分:0)

基于此问题How to break a tail -f command in bash,您可以尝试

#! /bin/bash

XMLF=/appl/logs/abc.log

aa_pam=${1-xml}
[[ ${2-xml} = "xml" ]] && tof=xml_$(date +%Y%m%d%H%M%S).xml || tof=$2

mkfifo log.pipe
tail -f "$XMLF" > log.pipe & tail_pid=$!

awk  -vpar1="$aa_pam" -vtof="$tof" -f t.awk  < log.pipe
kill $tail_pid
rm log.pipe

其中t.awk是:

/<\?xml version\=/ {
    if (Print_SW==1) {
        p_out(Cnt_Line)
    }
    Print_SW=0
    Cnt_line=0
}

{
    Trap_arry[++Cnt_line]=$0
}

$0 ~ par1 {
    Print_SW=1;
}

/<\/XYZ_999/    {
    if (Print_SW==1)
        p_out(Cnt_Line)
    Print_SW=0
    Cnt_line=0
}

function p_out(Cnt_Line, i) {
    for (i=1; i<Cnt_line; i++) {
        print Trap_arry[i] | ("tee " tof)
    }
    exit 1
}