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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36921658/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 14:34:36  来源:igfitidea点击:

Save command output on variable and check exit status

bash

提问by Nasr

The following command will resolve google ip

以下命令将解析google ip

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

Sometimes (especially when internet connection is lost) this command fail with this error

有时(尤其是当互联网连接丢失时)此命令会因此错误而失败

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

When the command fail and i use $#the output is 0 for the assigment

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

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

How could i save the output of command in variable, also check if the command succeeded

我如何将命令的输出保存在变量中,还要检查命令是否成功

采纳答案by sjsam

You should use $?instead of $#.

您应该使用 $?而不是$#.

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

Do something like below :

执行以下操作:

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

Edit :In reply to thiscomment answering the question in title :

编辑:回复评论,回答标题中的问题:

Save command output on variable and check exit status

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

As @chepnerpointed out in thiscomment, an assignment doesn't meddle with the exit status of command. So :

正如@chepner评论中指出的那样,赋值不会干扰命令的退出状态。所以 :

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

回答by Rany Albeg Wein

You can avoid accessing $?, and simply:

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

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

Example:

例子:

The following function will print "fail" and return 1.

以下函数将打印“失败”并返回 1。

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

Thus, if we do the following:

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

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

We'll get no output, yet store print_and_failoutput to $foo- in this case, "fail".

我们不会得到任何输出,但将print_and_fail输出存储到$foo- 在这种情况下,“失败”。

But, take a look at the following function, which will print "success" and return 0.

但是,看看下面的函数,它将打印“成功”并返回 0。

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

Let's see what happens now:

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

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

回答by David C. Rankin

You can check the return or use command-substitutionand check the resulting variable. e.g.

您可以检查返回或使用命令替换并检查结果变量。例如

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

(you can do the reverse check for failure with -z

(您可以对失败进行反向检查 -z

回答by Swiss

I recommend against the use of $?as much as possible, as it is fragile and easy to overlook when refactoring. If someone adds a line in between the command and $?, the script will break in non-obvious ways.

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

If you want to both assign the output to a variable and check the exit code at the same time, you can just do both in your conditional block:

如果您想同时将输出分配给变量并检查退出代码,您可以在条件块中同时执行:

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

echo "$foo"

回答by John Mark Mitchell

Since you are using Bash, you can use something like the following script which can capture stdout, stderr and the return code https://gist.github.com/jmmitchell/c4369acb8e9ea1f984541f8819c4c87b

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

For easy reference I have copied the script here:

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

# #!/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