使用awk退出时发生意外行为

时间:2018-07-13 08:49:05

标签: bash shell awk scripting exit

我有下一个代码:

process_mem() {
    used=`sed -n -e '/^Cpu(s):/p' $temp_data_file | awk '{print $2}' | sed 's/\%us,//'`
    idle=`sed -n -e '/^Cpu(s):/p' $temp_data_file | awk '{print $5}' | sed 's/\%id,//'`

    awk -v used=$used \
        -v custom_cpu_thres=$custom_cpu_thres \
        '{
            if(used>custom_cpu_thres){
                exit 1
            }else{
                exit 0
            }

        }'
    return=$?
    echo $return

    if [[ $return -eq 1 ]]; then
        echo $server_name"- High CPU Usage (Used:"$used".Idle:"$idle"). "
        out=1
    else 
        echo $server_name"- Normal CPU Usage (Used:"$used".Idle:"$idle"). "
    fi
}

while IFS='' read -r line || [[ -n "$line" ]]; do

    server_name=`echo $line | awk '{print $1}'`
    custom_cpu_thres=`echo $line | awk '{print $3}'`
    if [ "$custom_cpu_thres" = "-" ]; then
        custom_cpu_thres=$def_cpu_thres
    fi

    expect -f "$EXPECT_SCRIPT" "$command" >/dev/null 2>&1
    result=$?

    if [[ $result -eq 0 ]]; then
        process_mem 
    else 
        echo $server_name"- Error in Expect Script. "
        out=1
    fi
    echo $server_name
done < $conf_file

exit $out

问题是读取bash循环应执行4次(每行读取一次)。但是,如果我写的awk代码内部有出口,则在第一次循环后退出read bash循环。

为什么会这样?我认为awk代码中的退出代码不应该影响bash脚本。

致谢。

1 个答案:

答案 0 :(得分:2)

我相信您的陈述是错误的。

您说:

  

问题是读取bash循环应执行4次(每行读取一次)。但是,如果我写的awk代码内部有出口,则在第一个循环之后退出read bash循环。

我不认为该脚本在第一个循环后退出,但是卡在了第一个循环中。我这样做的原因是您的awk脚本有缺陷。您写的方式是:

awk -v used=$used -v custom_cpu_thres=$custom_cpu_thres \
    '{ if(used>custom_cpu_thres){ exit 1 }
       else{ exit 0 } }'

这里的问题是Awk没有获得输入文件。如果没有证明输入文件可以awk,它将读取stdin(类似于处理管道或键盘输入)。由于没有信息发送到stdin(除非您按下了几个键并且不小心按下了 Enter ),所以脚本将不会继续前进,并且Awk正在等待输入。

  

仅当未指定文件操作数或文件操作数为'-'或progfile选项参数为'-'时,才应使用标准输入。请参阅“输入文件”部分。如果awk程序不包含任何操作且没有任何模式,但它是有效的awk程序,则不应读取标准输入和任何文件操作数,并且awk应当以零返回状态退出。

     

来源:Awk POSIX Standard

以下bash行演示了以上语句:

$ while true; do awk '{print "woot!"; exit }'; done

仅当您按一些键,然后按 Enter 时,单词“ woot!”才响起。在屏幕上打印!

如何解决您的问题: 使用Awk解决问题的最简单方法是利用BEGIN块。该块在读取任何输入行(或stdin)之前执行。如果您告诉Awk在begin块中退出,它将终止Awk而不会读取任何输入。因此:

awk -v used=$used -v custom_cpu_thres=$custom_cpu_thres \
    'BEGIN{ if(used>custom_cpu_thres){ exit 1 }
            else{ exit 0 } }'

或更短

awk -v used=$used -v custom_cpu_thres=$custom_cpu_thres \
    'BEGIN{ exit (used>custom_cpu_thres) }

但是,Awk在这里有点过大。一个简单的bash测试就足够了:

[[ "$used" -le "$custom_cpu_thres" ]]
result=$?

(( used <= custom_cpu_thres ))
result=$?