【问题标题】:bash - returning value based on process conditionbash - 基于进程条件的返回值
【发布时间】:2019-02-21 05:12:24
【问题描述】:

我偶然发现了一种基于变量有条件地返回值的令人困惑的方式。我想检查进程是否成功然后回显“进程成功”,但是如果失败了,我想检查特定的错误消息然后返回错误消息,

ERRMSG="$(cd /nonexist 2>&1)"
if [ $? -ne 0 ]
then
    if [ -z "$ERRMSG|grep -o 'No such file or directory'|head -1" ]
    then
    echo "empty" >> $FQLOGNAME
    else
    echo $ERRMSG|grep -o 'No such file or directory'|head -1 >> $FQLOGNAME
    fi
else
echo "success" >> $FQLOGNAME
fi

请指教, 谢谢

【问题讨论】:

    标签: linux bash


    【解决方案1】:

    您不需要使用grep 来检查字符串是否包含子字符串。 Bash 中内置的模式匹配就足够了。这段代码应该做一些接近你想要的事情:

    if ERRMSG=$(cd /nonexist 2>&1) ; then
        echo 'process success'
    elif [[ $ERRMSG == *'No such file or directory'* ]] ; then
        echo 'No such file or directory'
    else
        echo 'empty'
    fi >> "$FQLOGNAME"
    

    有关[[...]] 的模式匹配功能的详细信息,请参阅Conditional Constructs section of the Bash Reference Manual

    我保留了ERRMSGFQLOGNAME 变量,但请注意最好避免使用ALL_UPPERCASE 变量名称。它们有可能与环境变量或 Bash 内置变量发生冲突。见Correct Bash and shell script variable capitalization

    要在多行错误消息中查找由某个模式定义的错误消息,并且只打印第一个,您可以在[[...]] 中使用正则表达式匹配 (=~)。为了提供一个具体示例,此代码假定错误消息由“ERROR”后跟一个或多个空格以及一个十进制数组成:

    # Example function for testing
    function dostuff
    {
        printf 'Output line A\n'
        printf 'Encountered ERROR 29\n' >&2
        printf 'Output line B\n'
        printf 'Encountered ERROR 105\n' >&2
        printf 'Output line C\n'
    
        return 1
    }
    
    # Regular expression matching an error string
    readonly error_rx='ERROR +[0-9]+'
    
    if ERRMSG=$(dostuff 2>&1) ; then
        echo 'process success'
    elif [[ $ERRMSG =~ $error_rx ]] ; then
        printf '%s\n' "${BASH_REMATCH[0]}"
    else
        echo 'empty'
    fi >> "$FQLOGNAME"
    

    它将“ERROR 29”附加到日志文件中。

    有关 Bash 内置正则表达式匹配的更多信息,请参阅mklement0's answer to "How do I use a regex in a shell script?"

    【讨论】:

    • 这是一个示例错误消息,因为我想执行 java 脚本,如果失败可能会返回多个错误消息,因此我需要 grep 并仅选择第一个匹配项,它是否适用于您的解决方案案例?
    • 我添加了试图满足明确要求的代码。
    【解决方案2】:

    让它更简单更容易:

    if ! ERRMSG=$(cd /nonexist 2>&1); then
         if <<<"$ERRMSG" grep -q 'No such file or directory'; then
               # if the error string contains the message 'No such file or directory'
               echo "empty" >> "$FQLOGNAME"
         else
               printf "Unhandled cd error: %s" "$ERRMSG" >> "$FQLOGNAME"
         fi
    else
         echo "process success" >> "$FQLOGNAME"
    fi
    
    1. if 语句检查命令的返回状态。 [test 只是一个返回状态的命令。赋值的返回状态与命令状态相同。我的意思是,out=$(cmd); if [ "$?" -eq 0 ]; thenif out=$(cmd); then 相同。
    2. 使用 HERE 字符串比 echo "$string" 好一点。 Echo 不太便携,最好习惯printf "%s" "$string",这是一种便携的方式。然而 HERE-strings 会在流的末尾添加额外的 EOF,这有时会破坏 while read 循环,但在大多数情况下都可以正常工作。
    3. 不要if [ -z "$(echo smth | grep ..)" ]; then。您可以只检查 grep 返回状态,只需 if echo smth | grep ...; then 或 HERE 字符串 if &lt;&lt;&lt;"smth" grep -q ...; thenif grep -q ... file; then。具有--quiet--silent 替代项的-q 选项使grep 不产生任何输出。
    4. 从单个命令替换分配变量时不需要引用。 tmp="$(...)"tmp=$(...) 相同。

    【讨论】:

    • 我并不完全相信这是“更简单、更容易”。
    • 谢谢,我会试试这个,但是这个 grep 是第一次匹配的唯一结果吗?
    • &lt;&lt;&lt;"$string" 被称为 HERE-string,它与echo "$string" | 或更专业的printf "%s" "$string" 相同。如果我理解正确,如果 ERRMSG 包含“没有这样的文件或目录”,您想在日志文件中打印“空”。所以脚本会这样做,从第二行读取:如果 ERRMSG contains/greps 'No such file or directory, then print empty to FQLOGNAME eles print unhandled cd error to FQLOGNAME.
    猜你喜欢
    • 2017-05-24
    • 1970-01-01
    • 2021-08-05
    • 2016-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-05
    相关资源
    最近更新 更多