在变量上保存命令输出并检查退出状态

时间:2016-04-28 17:31:01

标签: bash

以下命令将解析google ip

> ip=`dig +short google.com`
> echo $ip
> 216.58.210.238

有时(特别是当互联网连接丢失时)此命令失败并显示此错误

> ;; connection timed out; no servers could be reached

当命令失败并且我使用$#时,分配的输出为0

> ip=`dig +short google.com`
> echo $#
> 0
> echo $ip     # Command failed
> ;; connection timed out; no servers could be reached

如何在变量中保存命令输出,同时检查命令是否成功

5 个答案:

答案 0 :(得分:6)

您可以避免访问$?,只需:

if ip=$(dig +short google.com); then
    # Success.
else
    # Failure.
fi

实施例

以下功能将打印“失败”并返回1.

print_and_fail() { printf '%s' fail; return 1; }

因此,如果我们执行以下操作:

if foo=$(print_and_fail); then printf '%s\n' "$foo";fi

我们没有输出,但是将print_and_fail输出存储到$foo - 在这种情况下,“失败”。

但是,看一下下面的函数,它会打印“success”并返回0。

print_and_succeed() { printf '%s' success; return 0; }

让我们看看现在发生了什么:

$ if foo=$(print_and_succeed); then printf '%s\n' "$foo";fi
$ success

答案 1 :(得分:2)

您应该使用$?代替$#

$? - contains the return value from the last script.
$# - contains the total number of arguments passed to a script or function

执行以下操作:

if $?
then
echo "Success" # Do something here
else
echo "Fail" # Fallback mode
fi

修改:回复this评论回答标题中的问题:

  

在变量上保存命令输出并检查退出状态

@chepnerthis注释中指出,分配并不干涉命令的退出状态。所以:

ip=$(dig +short google.com) # Just changed the legacy backticks to $()
[ $? -eq 0 ] && echo "dig succeeded"

答案 2 :(得分:1)

您可以检查返回或使用命令替换并检查生成的变量。 e.g。

yp

(您可以使用$ ip=$(dig +short google.com) $ [ -n "$ip" ] && echo "all good, ip = $ip"

反向检查失败

答案 3 :(得分:1)

我建议尽量不要使用$?,因为它易碎并且在重构时容易被忽略。如果有人在命令和$?之间添加了一行,则脚本将以不明显的方式中断。

如果要同时将输出分配给变量并同时检查退出代码,则可以在条件块中同时进行这两个操作:

if foo="$(echo "foo"; true)"; then
    echo "$foo"
fi

echo "$foo"

答案 4 :(得分:-1)

由于您使用的是Bash,因此您可以使用类似以下脚本的内容来捕获stdout,stderr和返回代码https://gist.github.com/jmmitchell/c4369acb8e9ea1f984541f8819c4c87b

为方便参考,我在这里复制了脚本:

# #!/bin/bash
# 
# based on posts from stackexchange:
# http://stackoverflow.com/a/26827443/171475
# http://stackoverflow.com/a/18086548/171475
# http://stackoverflow.com/a/28796214/171475

function example_function {
    printf 'example output to stdout %d\n' {1..10}
    echo >&2 'example output to stderr'
    return 42
}



##############################
### using the dot operator ###

if [ "${BASH_VERSINFO}" -lt 4 ]; then
    printf '%s\n' "The source version of this script requires Bash v4 or higher."
else

    # stdout & stderr only
    source <({ cmd_err=$({ mapfile -t cmd_out < <(example_function); } 2>&1; declare -p cmd_out >&2); declare -p cmd_err; } 2>&1)

    printf "\n%s\n" "SOURCE VERSION : STDOUT & STDERR ONLY"
    printf "%s\n" "${cmd_out[@]}"
    printf "%s\n" "${cmd_err}"

    unset cmd_out
    unset cmd_err


    # stdout & stderr only as well as return code:
    source <({ cmd_err=$({ mapfile -t cmd_out< <( \
        example_function \
      ; cmd_rtn=$?; declare -p cmd_rtn >&3); } 3>&2 2>&1; declare -p cmd_out >&2); declare -p cmd_err; } 2>&1)


    printf "\n%s\n" "SOURCE VERSION : STDOUT, STDERR & RETURN CODE"
    printf '%s\n' "${cmd_out[@]}"
    # alternative version
    # declare -p cmd_out 
    printf '%s\n' "${cmd_err}"
    printf '%s\n' "${cmd_rtn}"

    unset cmd_out
    unset cmd_err
    unset cmd_rtn

fi

##############################
######### using exec #########

# stdout & stderr only
eval "$({ cmd_err=$({ cmd_out=$( \
    example_function \
  ); } 2>&1; declare -p cmd_out >&2); declare -p cmd_err; } 2>&1)"

printf "\n%s\n" "EVAL VERSION : STDOUT & STDERR ONLY"
printf '%s\n' "${cmd_out}"
printf '%s\n' "${cmd_err}"
printf '%s\n' "${cmd_rtn}"

unset cmd_out
unset cmd_err

# stdout & stderr only as well as return code:
eval "$({ cmd_err=$({ cmd_out=$( \
    example_function \
  ); cmd_rtn=$?; } 2>&1; declare -p cmd_out cmd_rtn >&2); declare -p cmd_err; } 2>&1)"


printf "\n%s\n" "EVAL VERSION : STDOUT, STDERR & RETURN CODE"
printf '%s\n' "${cmd_out}"
printf '%s\n' "${cmd_err}"
printf '%s\n' "${cmd_rtn}"


unset cmd_out
unset cmd_err
unset cmd_rtn