Search code examples
awkpipetail

tail -f | awk and end tail once data is found


I am trying to build a script which tail -f | awk the log file which is getting updated every second. awk part will fetch me only the required part of the log file based on my search parameter. Output XML is also captured in an output file. Script is working fine - as expected.

Issue - However ever after the search is performed it stays hung due to tail -f. Any idea how to update below script - so that once the output XML is captured, it should break the tail part??

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

Update Tried as per below suggestion of using exit - it is existing the script successfully - however the xml that is getting captured at output is getting duplicated. So in the output file - same XML appears twice..!!

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

Solution

  • Based on this question How to break a tail -f command in bash you could try

    #! /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
    

    where t.awk is:

    /<\?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
    }