成功した場合は、パイプされたコマンドの結果を割り当てます。

成功した場合は、パイプされたコマンドの結果を割り当てます。

コマンドが失敗しなかった場合にのみ、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

これは間違いなく機能しますが、変数を2回割り当てるのは好きではありませんa

私はこれを試しました:

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

しかし、何も記録しません

もっと良い方法がありますか?

答え1

set -o pipefail以下を使用して、パイプラインの前の部分でエラーを取得できます。

パイプの戻り状態は、最後のコマンドの終了状態です。パイプ故障オプションが有効です。もしパイプ故障有効にすると、パイプの戻り状態は、ゼロ以外の状態で終了した最後の(最も右側の)コマンドの値、またはすべてのコマンドが正常に終了した場合は0です。

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

しかし、実際にはなぜ2回割り当てることが問題になるのか理解できません。デフォルトでは、コマンドが成功すると取得した値を変更し、コマンドが失敗した場合は無視します。

あるいは、そのロジックを少し圧縮することもできます。

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

シェルには、文字列の最初の単語を解析するいくつかの基本的なメソッドがあります。

  1. サフィックスでトリムする -${a%% *}

  2. 位置引数に代入 -set -- ${a}結果はにあります$1。を使用してこれを簡素化できますset -- $(func 1)

  3. bash(のみ)配列要素に分割 - a=( $(func 1) )- 結果はにあります${a[0]}

答え3

aコードの問題の1つは、関数が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"

ご覧のとおり、2番目のケースではaその値が保持されます。

関連情報