如果成功则分配管道命令的结果

如果成功则分配管道命令的结果

仅当命令没有失败时,我才想将a命令结果的第一个字分配给我的变量。func <some_arg>如果失败了,我需要记录下来。

到目前为止我所做的是:

func() {
    if [[ $1 -eq 1 ]]
    then
        echo 'hello world'
        return 0
    fi

    echo 'Something wrong has happened!' >> path/to/dev.log
    return 2
}

a=$(func 1)
r=$?

if [[ $r -eq 0 ]]
then
    a=$(awk '{ print $1 }' <<<"$a")
fi

这当然有效,但我不喜欢将变量分配a两次。

我试过这个:

  a=$(func 2 | awk '{ print $1 }') || echo 'Something wrong has happened!' >> path/to/dev.log

但它不记录任何内容

有没有更好的办法?

答案1

您可以使用set -o pipefail从管道的早期部分获取错误:

管道的返回状态是最后一个命令的退出状态,除非管道故障选项已启用。如果管道故障启用后,管道的返回状态是最后一个(最右边)以非零状态退出的命令的值,如果所有命令都成功退出,则返回零。

$ foo() { [[ "$1" = 1 ]] || return 1; echo "hello world"; }
$ a=$(set -o pipefail; foo 2 | awk '{print $1}' || echo "fail..." >&2)
fail...

但实际上,我不明白为什么分配两次会成为问题。本质上,如果命令成功,您只需修改获得的值,如果命令失败,则忽略它。

另外,您可以稍微压缩一下该逻辑:

if a=$(foo 1); then
   a=${a%% *};
   echo "first word of a is '$a'"; 
   # do some work with $a...
else
   echo "error..." >&2;
fi

印刷

first word of a is 'hello'

答案2

shell 有几种本地方法来解析字符串的第一个单词:

  1. 按后缀修剪 -${a%% *}

  2. 分配给位置参数 -set -- ${a}结果将在$1.您可以使用 来简化此操作set -- $(func 1)

  3. bash(仅)划分为数组元素- a=( $(func 1) )- 结果将在${a[0]}.

答案3

a您的代码的一个问题是,即使函数func返回非零结果,它也会崩溃。

反而:

#!/bin/sh

func () {
    if [ "$1" -eq 1 ]; then
        echo 'some sort of logging stuff' >>logfile
        return 1
    fi

    echo 'hello world'
}

a="a string"

if b=$( func 0 ); then
    a=${b%% *}
fi

printf '1: a = "%s"\n' "$a"

a="a string"

if b=$( func 1 ); then
    a=${b%% *}
fi

printf '2: a = "%s"\n' "$a"

运行这个会产生

1: a = "hello"
2: a = "a string"

正如您所看到的,在第二种情况下,a保留了其价值。

相关内容