GNU/Linux >> Linux の 問題 >  >> Linux

「-oErrtrace」(つまり、Set -e)を使用したコマンド置換でのエラーのトラップ?

この参照マニュアルによると:

-E(また-o errtrace)

設定されている場合、ERRのトラップは、シェル関数、コマンド置換、およびサブシェル環境で実行されるコマンドによって継承されます。
ERRトラップは通常、このような場合には継承されません。

ただし、以下は機能しないため、誤って解釈している必要があります。

#!/usr/bin/env bash
# -*- bash -*-

set -e -o pipefail -o errtrace -o functrace

function boom {
  echo "err status: $?"
  exit $?
}
trap boom ERR


echo $( made up name )
echo "  ! should not be reached ! "

私はすでに簡単な割り当てを知っています、 my_var =$(made_up_name) set -eを使用してスクリプトを終了します (つまり、errexit)。

-E / -o errtraceです 上記のコードのように動作するはずですか?または、おそらく、私はそれを読み間違えましたか?

承認された回答:

注: zsh ここでのほとんどの例で「インラインコメント」を受け入れるように構成せず、 sh <<-CMD <で行ったようにプロキシシェルを介して実行しないと、「悪いパターン」について文句を言います。 / code> 。

さて、上記のコメントで述べたように、bashのset -Eについて具体的にはわかりません。 、しかし、POSIX互換シェルは、必要に応じて値をテストする簡単な手段を提供することを知っています:

    sh -evx <<-CMD
    _test() { echo $( ${empty:?error string} ) &&
        echo "echo still works" 
    }
    _test && echo "_test doesnt fail"
    # END
    CMD
sh: line 1: empty: error string
+ echo

+ echo 'echo still works'
echo still works
+ echo '_test doesnt fail'
_test doesnt fail

上記では、パラメータ拡張を使用したことがわかります。 $ {empty?} _test()をテストするには それでもreturn s パス–最後の echoで明らかなように これは、失敗した値が $(コマンド置換)を強制終了するために発生します それを含むサブシェルですが、その親シェル– _test 現時点では–トラックを続けます。そしてecho 気にしない–改行だけを提供するのはとても幸せです。エコー ない テスト。

しかし、これを考慮してください:

    sh -evx <<-CMD
    _test() { echo $( ${empty:?error string} ) &&
            echo "echo still works" ; } 2<<-INIT
            ${empty?function doesnt run}
    INIT
    _test ||
            echo "this doesnt even print"
    # END
    CMD
_test+ sh: line 1: empty: function doesnt run

_test()のをフィードしたため INIT here-documentに事前評価されたパラメータを使用して入力する 現在、 _test() 関数はまったく実行を試みません。さらにsh シェルは明らかにゴーストを完全に放棄し、エコー「これは印刷すらしません」 印刷すらしません。

おそらくそれはではありません 欲しいもの。

これは、 $ {var?}が原因で発生します style parameter-expansionは、 shellを終了するように設計されています パラメータが欠落している場合は、次のように機能します。

$ {parameter:?[word]}

Nullの場合はエラーを示します または未設定。 パラメータが設定されていないかnullの場合、単語の拡張 (または単語が省略されている場合は未設定であることを示すメッセージ)標準エラーに書き込まれる シェルはゼロ以外の終了ステータスで終了します それ以外の場合は、parameterの値が置き換えられます インタラクティブシェルを終了する必要はありません。

ドキュメント全体をコピーして貼り付けることはしませんが、 set but nullで失敗したい場合 フォームを使用する値:

$ {var 😕 エラーメッセージ}

:colonを使用 上記のように。 nullが必要な場合 成功する値。コロンを省略してください。後で説明するように、これを無効にして、設定値に対してのみ失敗することもできます。

_test()の別の実行:

    sh <<-CMD
    _test() { echo $( ${empty:?error string} ) &&
            echo "echo still works" ; } 2<<-INIT
            ${empty?function doesnt run}
    INIT
    echo "this runs" |
        ( _test ; echo "this doesnt" ) ||
            echo "now it prints"
    # END
    CMD
this runs
sh: line 1: empty: function doesnt run
now it prints

これはあらゆる種類のクイックテストで機能しますが、上に _test()が表示されます。 パイプラインの中央から実行します 失敗し、実際にはコマンドリストが含まれています 関数内のコマンドも次のecho も実行されないため、サブシェルは完全に失敗します まったく実行しますが、 echo "now it prints" であるため、簡単にテストできることも示されています。 印刷します。

悪魔は細部に宿っていると思います。上記の場合、終了するシェルはではありません スクリプトの_main |ロジック|パイプライン しかし、 ($ {test?}が含まれるサブシェル)|| そのため、少しサンドボックス化が必要です。

関連:rootとしてアプリを開くことができません。 sudoコマンドが見つかりませんか?

そして、それは明白ではないかもしれませんが、反対の場合にのみ合格したい場合、または set =のみに合格したい場合 値、それもかなり簡単です:

    sh <<-CMD
    N= #N is NULL
    _test=$N #_test is also NULL and
    v="something you would rather do without"    
    ( #this subshell dies
        echo "v is ${v+set}: and its value is ${v:+not NULL}"
        echo "So this ${_test:-"$_test:="} will equal ${_test:="$v"}"
        ${_test:+${N:?so you test for it with a little nesting}}
        echo "sure wish we could do some other things"
    )
    ( #this subshell does some other things 
        unset v #to ensure it is definitely unset
        echo "But here v is ${v-unset}: ${v:+you certainly wont see this}"
        echo "So this ${_test:-"$_test:="} will equal NULL ${_test:="$v"}"
        ${_test:+${N:?is never substituted}}
        echo "so now we can do some other things" 
    )
    #and even though we set _test and unset v in the subshell
    echo "_test is still ${_test:-"NULL"} and ${v:+"v is still $v"}"
    # END
    CMD
v is set: and its value is not NULL
So this $_test:= will equal something you would rather do without
sh: line 7: N: so you test for it with a little nesting
But here v is unset:
So this $_test:= will equal NULL
so now we can do some other things
_test is still NULL and v is still something you would rather do without

上記の例では、POSIXパラメーター置換の4つの形式すべてと、それらのさまざまな :colon nullを利用しています。 またはnot null テスト。上記のリンクに詳細がありますが、ここに再びあります。

そして、 _testを表示する必要があると思います 機能も機能しますよね? empty =somethingを宣言するだけです 関数のパラメーターとして(または事前に):

    sh <<-CMD
    _test() { echo $( echo ${empty:?error string} ) &&
            echo "echo still works" ; } 2<<-INIT
            ${empty?tested as a pass before function runs}
    INIT
    echo "this runs" >&2 |
        ( empty=not_empty _test ; echo "yay! I print now!" ) ||
            echo "suspiciously quiet"
    # END
    CMD
this runs
not_empty
echo still works
yay! I print now!

この評価は独立していることに注意してください。失敗するために追加のテストは必要ありません。さらにいくつかの例:

    sh <<-CMD
    empty= 
    ${empty?null, no colon, no failure}
    unset empty
    echo "${empty?this is stderr} this is not"
    # END
    CMD
sh: line 3: empty: this is stderr

    sh <<-CMD
    _input_fn() { set -- "[email protected]" #redundant
            echo ${*?WHERES MY DATA?}
            #echo is not necessary though
            shift #sure hope we have more than $1 parameter
            : ${*?WHERES MY DATA?} #: do nothing, gracefully
    }
    _input_fn heres some stuff
    _input_fn one #here
    # shell dies - third try doesnt run
    _input_fn you there?
    # END
    CMD
heres some stuff
one
sh: line :5 *: WHERES MY DATA?

そして最後に、元の質問に戻ります。 $(コマンド置換)でエラーを処理する方法 サブシェル? 真実は– 2つの方法がありますが、どちらも直接ではありません。問題の核心は、シェルの評価プロセス–シェル拡張( $(コマンド置換)を含む)です。 )現在のシェルコマンドの実行よりもシェルの評価プロセスの早い段階で発生します。これは、エラーがキャッチされてトラップされる可能性がある場合です。

opが経験する問題は、現在のシェルがエラーを評価するまでに、<​​em> $(コマンド置換) サブシェルはすでに置き換えられています–エラーは残っていません。

では、2つの方法は何ですか? $(コマンド置換)内で明示的に実行するか サブシェルを使用しない場合と同じようにテストを使用するか、その結果を現在のシェル変数に吸収してその値をテストします。

関連:PostgreSQL Selectステートメントはdatagripでエラーを生成しますが、pgAdmin4ではエラーを生成しませんか?

方法1:

    echo "$(madeup && echo : || echo '${fail:?die}')" |
          . /dev/stdin

sh: command not found: madeup
/dev/stdin:1: fail: die

    echo $?

126

方法2:

    var="$(madeup)" ; echo "${var:?die} still not stderr"

sh: command not found: madeup
sh: var: die

    echo $?

1

これは、1行あたりに宣言された変数の数に関係なく
失敗します:

   v1="$(madeup)" v2="$(ls)" ; echo "${v1:?}" "${v2:?}"

sh: command not found: madeup
sh: v1: parameter not set

そして、戻り値は一定のままです:

    echo $?
1

今すぐトラップ:

    trap 'printf %s\n trap resurrects shell!' ERR
    v1="$(madeup)" v2="$(printf %s\n shown after trap)"
    echo "${v1:?#1 - still stderr}" "${v2:?invisible}"

sh: command not found: madeup
sh: v1: #1 - still stderr
trap
resurrects
shell!
shown
after
trap

    echo $?
0

Linux
  1. コマンド置換:改行で分割するがスペースでは分割しない?

  2. 「?」を使用したコマンド置換

  3. .bashrcでエクスポートを使用しますか?

  1. エコーコマンドでフォントを変更しますか?

  2. scpコマンドを使用する10の実際的な例

  3. シェルコマンドを使用してGDB内で環境変数を設定するには?

  1. socatを使用したTCPプロキシ

  2. Cronを使用してLinuxVPSでタスクの自動化を設定するにはどうすればよいですか?

  3. エコー:コマンドが見つかりません