AWK脚本中的嵌套getline

时间:2012-12-14 07:01:08

标签: shell unix awk

如果我们可以在AWK脚本中使用嵌套的getline,请告知我们:

while ( ("tail -f log" |& getline var0) > 0) {

    while ( ("ls" | getline ) > 0) {
    }
    close("ls")
    while ( ("date" | getline ) > 0) {
    }
    close("date")
}
    close("tail -f log")

我们可以利用嵌套getline功能的深度是多少,并且在嵌套getline的任何级别都会有输出数据丢失吗?在实施这种风格时我们应该确定哪些事情?

=============================================== ===================================

UPDATE =================== UPDATE ============== UPDATE =========== ==== UPDATE =======

要求:通过探测QA框和网络服务器/服务日志和系统状态,提供实时统计数据和错误。报告将按以下格式生成:

当地日期和时间|分类|组件|条件

假设 - : AWK脚本的执行速度比shell脚本快,并且还具有使用内置解析和其他功能的优势。

实施: - 主命令循环是command0 =“tail -f -n 0 -s 5 ...........”。此命令将启动无限循环,提取QA框的服务/网络服务器的附加日志。 。请注意-f,-s和-n选项,它们将所有附加数据转储到日志中,在每次迭代后休眠5秒钟,然后从现有日志中打印任何默认内容开始。

每次迭代后,捕获并验证系统时间并在10秒间隔后执行各种OS资源命令(每次迭代之间5秒睡眠和处理尾部输出后4秒 - 假设处理所有尾部命令大致取1秒,因此在所有10秒内)

我用于提取OS资源的各种命令是:

I.  command1="vmstat | nl | tr -s '\\t '"
II. command2="sar -W 0"
III.    command3="top -b -n 1 | nl | tr -s '\\t '"
IV. command4="ls -1 /tmp | grep EXIT"

在脚本中搜索相应的命令(?),然后在脚本中通过while循环来计算相应命令的输出处理。注意我使用'nl'命令进行开发/编码轻松

最终在框中存在/ tmp / EXIT文件会使脚本从框中删除后退出

下面是我的脚本 - 我已经尽可能地添加了自我解释的注释:

#Useage - awk -f script.awk
BEGIN {
    command0="tail -f -n 0 -s 5 /x/web/webserver/*/logs/error_log /x/web/webserver/service/*/logs/log"
    command1="vmstat | nl | tr -s '\\t '"
    command2="sar -W 0"
    command3="top -b -n 1 | nl | tr -s '\\t '"
    command4="ls -1 /tmp | grep EXIT"
    format = "%a %b %e %H:%M:%S %Z %Y"
    split("", details)
    split("", fields)
    split("", data)
    split("", values)
    start_time=0

    printf "\n>%s:\n\n", command0 #dummy print for debuggng command being executed

    while ( (command0 |& getline var0) > 0) { #get the command output
        if (start_time == 0) #if block to reset the start_time variable
        {
                start_time = systime() + 4
        }
        if (var0 ~ /==>.*<==/) { #if block to extract the file name from the tail output - outputted in '==>FileName<==' format
                gsub(/[=><]/, "", var0)
                len = split(var0, name, "/")
                if(len == 7) {file = name[5]} else {file = name[6]}
        }
        if (len == 7 && var0 ~ /[Ee]rror|[Ee]xception|ORA|[Ff]atal/) {  #extract the logs error statements
                print strftime(format,systime()) " | Error Log | " file " | Error :" var0
        }
        if(systime() >= start_time) #check if curernt system time is greater than start_time as computed above
        {
                start_time = 0 #reset the start_time variable and now execute the system resource command
                printf "\n>%s:\n\n", command1
                while ( (command1 |& getline) > 0) { #process output of first command
                if($1 <= 1)
                        continue #not needed for processing skip this one
                if($1 == 2) #capture the fieds name and skip to next line
                {
                        for (i = 1; i <= NF; i++){fields[$i] = i;}
                        continue
                }
                if ($1 == 3) #store the command data output in data array
                        split($0, data);
                print strftime(format,systime()) " | System Resource | System | Time spent running non-kernel code :" data[fields["us"]]
                print strftime(format,systime()) " | System Resource | System | Time spent running kernel code :" data[fields["sy"]]
                print strftime(format,systime()) " | System Resource | System | Amount of memory swapped in from disk :" data[fields["si"]]
                print strftime(format,systime()) " | System Resource | System | Amount of memory swapped to disk :" data[fields["so"]]
                }
                close(command1)

                printf "\n>%s:\n\n", command2 #start processing second command
                while ( (command2 |& getline) > 0) {
                        if ($4 ~ /[0-9]+[\.][0-9]+/) #check for 4th positional value if its format is of "int.intint" format
                        {
                                if( $4 > 0.0) #dummy check now to print if page swapping
                                        print strftime(format,systime()) " | System Resource | Disk | Page rate is > 0.0 reads/second: " $4
                        }
                }
                close(command2)

                printf "\n>%s:\n\n", command3 # start processing command number 3
                while ( (command3 |& getline ) > 0) {
                        if($1 == 1 && $0 ~ /load average:/) #get the load average from the output if this is the first line
                        {
                                split($0, arr, ",")
                                print strftime(format,systime())" | System Resource | System |" arr[4]
                        }
                        if($1 > 7 && $1 <= 12) # print first top 5 process that are consuming most of the CPUs time
                        {
                                f=split($0, arr, " ")
                                if(f == 13)
                                        print strftime(format,systime())" | System Resource | System | CPU% "arr[10]" Process No: "arr[1] - 7" Name: "arr[13]
                        }
                }
                close(command3)
                printf "\n>%s:\n\n", command4 #process command number 4 to check presence of file
                while ( (command4 |& getline var4) > 0) {
                        system("rm -rf /tmp/EXIT")
                        exit 0 #if file is there then remove the file and exit this script execution
                }
                close(command4)
        }
    }
        close(command0)
}

输出 - :

>tail -f -n 0 -s 5 /x/web/webserver/*/logs/error_log /x/web/webserver/service/*/logs/log:


>vmstat | nl | tr -s '\t ':

Sun Dec 16 23:05:12 PST 2012 | System Resource | System | Time spent running non-kernel code :9
Sun Dec 16 23:05:12 PST 2012 | System Resource | System | Time spent running kernel code :9
Sun Dec 16 23:05:12 PST 2012 | System Resource | System | Amount of memory swapped in from disk :0
Sun Dec 16 23:05:12 PST 2012 | System Resource | System | Amount of memory swapped to disk :2

>sar -W 0:

Sun Dec 16 23:05:12 PST 2012 | System Resource | Disk | Page rate is > 0.0 reads/second: 3.89

>top -b -n 1 | nl | tr -s '\t ':

Sun Dec 16 23:05:13 PST 2012 | System Resource | System | load average: 3.63
Sun Dec 16 23:05:13 PST 2012 | System Resource | System | CPU% 12.0 Process No: 1 Name: occworker
Sun Dec 16 23:05:13 PST 2012 | System Resource | System | CPU% 10.3 Process No: 2 Name: occworker
Sun Dec 16 23:05:13 PST 2012 | System Resource | System | CPU% 6.9 Process No: 3 Name: caldaemon
Sun Dec 16 23:05:13 PST 2012 | System Resource | System | CPU% 6.9 Process No: 4 Name: occmux
Sun Dec 16 23:05:13 PST 2012 | System Resource | System | CPU% 6.9 Process No: 5 Name: top

>ls -1 /tmp | grep EXIT:

1 个答案:

答案 0 :(得分:6)

这是你回忆起关于以这种方式使用getline的第二篇文章。我上次提到这是错误的方法,但看起来你不相信我,所以让我再试一次。

您的问题“我如何使用awk执行带getline的命令来读取输出?”就像问“我如何使用钻头切割玻璃?”。你可以得到一个答案,告诉你把你要钻的玻璃部分贴在上面,以避免它破裂,这样可以回答你的问题,但更有用的答案可能就是 - 不要这样做,不要用玻璃刀

使用awk作为从中调用命令的shell是100%错误的方法。只需使用合适的工具即可完成正确的工作。如果需要解析文本文件,请使用awk。如果您需要操作文件或进程或调用命令,请使用shell(或等效的OS)。

最后,请阅读http://awk.freeshell.org/AllAboutGetline,在完全理解所有注意事项之前,请不要考虑使用getline。

编辑:这是一个shell脚本来执行你发布的awk脚本所做的事情:

tail -f log |
while IFS= read -r var0; do
    ls
    date
done

看起来更简单?不是说这样做是有意义的,但是如果你确实想要这样做,那就是实现它的方式,而不是awk。

编辑:这里是如何在shell中编写你的awk脚本的第一部分(在这种情况下是bash),我没有热情为你翻译剩下的部分,我想这会告诉你如何自己做其余的事情:

format = "%a %b %e %H:%M:%S %Z %Y"
start_time=0

tail -f -n 0 -s 5 /x/web/webserver/*/logs/error_log /x/web/webserver/service/*/logs/log |
while IFS= read -r line; do

    systime=$(date +"%s")

    #block to reset the start_time variable
    if ((start_time == 0)); then
        start_time=(( systime + 4 ))
    fi

    #block to extract the file name from the tail output - outputted in '==>FileName<==' format
    case $var0 in
        "==>"*"<==" )
            path="${var0%% <==}"
            path="${path##==> }"
            name=( ${path//\// } )
            len="${#name[@]}"
            if ((len == 7)); then
                file=name[4]
            else
                file=name[5]
            fi
            ;;
    esac

    if ((len == 7)); then
        case $var0 in
            [Ee]rror|[Ee]xception|ORA|[Ff]atal )    #extract the logs error statements
                printf "%s | Error Log | %s | Error :%s\n" "$(date +"$format")" "$file" "$var0"
                ;;
        esac
    fi

    #check if curernt system time is greater than start_time as computed above
    if (( systime >= start_time )); then

        start_time=0 #reset the start_time variable and now execute the system resource command
        ....

请注意,这会比你的awk脚本执行得稍快,但这完全没关系,因为你的尾巴在迭代之间需要5秒钟的休息时间。

另请注意,我上面所做的就是将你的awk脚本翻译成shell,这并不一定意味着它是从头开始编写这个工具的最好方法。