【问题标题】:Unexpected behaviour with awk exitawk 退出的意外行为
【发布时间】:2018-07-13 08:49:04
【问题描述】:

我有下一个代码:

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 代码,则在第一个循环之后读取 bash 循环退出。

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

问候。

【问题讨论】:

  • 您好,欢迎来到 Stack Overflow。你能创建一个我们可以用来解决这个问题的小脚本吗?在当前状态下,我们无法验证您的发现并帮助您解决问题或解释罪魁祸首。 (minimal reproducible example)。

标签: bash shell awk scripting exit


【解决方案1】:

我认为你的说法是错误的。

你说:

问题是读取 bash 循环应该执行 4 次(每行读取一次)。但是,如果我编写带有退出的 awk 代码,则读取 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(类似于处理管道或键盘输入)。由于没有信息发送到标准输入(除非您按了几个键并意外按了 Enter),因此脚本不会继续前进,并且 Awk 正在等待输入。

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

来源:Awk POSIX Standard

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

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

只有当您按下某些键后跟 Enter 时,才会出现“woot!”这个词打印在屏幕上!

如何解决您的问题: 使用 Awk 解决问题的最简单方法是使用 BEGIN 块。该块在读取任何输入行(或stdin)之前执行。如果您告诉 Awk 在开始块中退出,它将终止 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=$?

【讨论】:

  • 非常好!而且您太好了,更不用说整个脚本可能可以用 awk 重写,而无需调用外部。例如used=`sed -n -e '/^Cpu(s):/p' $temp_data_file | awk '{print $2}' | sed 's/\%us,//'`,可以是awk '/^Cpu(s):/{used=$2;sub(/\%us,/"",used); print used}' $temp_data_file,当然所有其他变量都可以类似地捕获,并在awk中进行测试,而无需调用外部程序。 O.P. 请注意 ;-) 。祝大家好运!
猜你喜欢
  • 1970-01-01
  • 2016-08-02
  • 2016-08-11
  • 2013-08-17
  • 2016-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多