0

请让我知道我们是否可以在 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 的任何级别都会有任何输出数据丢失吗?在实现这种风格时,我们应该确保哪些事情?

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

更新===================更新==============更新============= =更新=======

要求:通过探测 QA box 和 webserver/services 日志和系统状态提供实时统计数据和错误。报告将按以下格式生成:

本地日期和时间 | 类别| 组件 | 健康)状况

假设 -: AWK 脚本将比 shell 脚本执行得更快,并具有使用其内置解析和其他功能的额外优势。

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

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

我用于提取操作系统资源的各种命令是:

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:
4

1 回答 1

6

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

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

使用 awk 作为调用命令的 shell 是 100% 错误的方法。只需为正确的工作使用正确的工具。如果需要解析文本文件,请使用 awk。如果您需要操作文件或进程或调用命令,请使用 shell(或您的操作系统等效项)。

最后,请阅读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 脚本执行得稍快一些,但这绝对无关紧要,因为您的 tail 在迭代之间需要 5 秒的休息时间。

另请注意,我上面所做的只是将您的 awk 脚本转换为 shell,这并不一定意味着它是从头开始编写此工具的最佳方式。

于 2012-12-14T13:43:14.007 回答