割り当ては、コマンド置換がある場合を除いて、終了ステータスを持つコマンドに似ていますか?


10

次の例とそれらのPOSIXシェルでの出力を参照してください。

  1. false;echo $?またはfalse || echo 11
  2. false;foo="bar";echo $?またはfoo="bar" && echo 00
  3. foo=$(false);echo $?またはfoo=$(false) || echo 11
  4. foo=$(true);echo $?またはfoo=$(true) && echo 00

/programming/6834487/what-is-the-variable-in-shell-scriptingの最高投票の回答で述べたように:

$? 最後に実行されたコマンドの戻り値を見つけるために使用されます。

これはおそらくこの場合少し誤解を招く可能性があるので、そのスレッドからの投稿でも引用されているPOSIX定義を取得しましょう。

?最新のパイプラインの10進数の終了ステータスに展開します(パイプラインを参照)。

したがって、割り当て自体はゼロの終了値を持つコマンド(またはパイプラインパーツ)としてカウントされているように見えますが、割り当ての右側のに適用されます(たとえば、ここでの例ではコマンド置換呼び出し)。

この振る舞いが実用的な見地からどのように意味を成すかはわかりますが、割り当て自体がその順序でカウントされることは、私には幾分珍しいようです。多分それが私にとって奇妙な理由をより明確にするために、割り当てが関数であったと仮定しましょう:

ASSIGNMENT( VARIABLE, VALUE )

そしてfoo="bar"だろう

ASSIGNMENT( "foo", "bar" )

foo=$(false)ようなものになります

ASSIGNMENT( "foo", EXECUTE( "false" ) )

そのことを意味するEXECUTE実行が最初後にのみ ASSIGNMENT実行されますが、それはまだだEXECUTEここで問題のステータス。

私の評価は正しいですか、それとも何かを誤解/不足していますか?これらは、私がこの振る舞いを「奇妙な」ものと見なす正しい理由ですか?


1
申し訳ありませんが、何がおかしいのかはわかりません。
クサラナンダ

1
@Kusalananda多分それは私が自分自身に尋ねることから始まったことをあなたに伝えるのに役立つかもしれません:false;foo="bar";echo $?実行された最後の実際のコマンドがなぜなぜいつも0を返すのfalseですか?」基本的に、割り当ては終了コードに関して特別な動作をします。それらの終了コードは、割り当ての右側の一部として実行された何かが原因ではない場合を除いて、常に0です。
2017年

回答:


10

割り当ての終了ステータスがおかしい。割り当てが失敗する最も明白な方法は、ターゲット変数がマークされてreadonlyいる場合です。

$ err(){ echo error ; return ${1:-1} ; }
$ PS1='$? $ '
0 $ err 42
error
42 $ A=$(err 12)
12 $ if A=$(err 9) ; then echo wrong ; else E=$? ; echo "E=$E ?=$?" ; fi
E=9 ?=0
0 $ readonly A
0 $ if A=$(err 10) ; then echo wrong ; else E=$? ; echo "E=$E ?=$?" ; fi
A: is read only
1 $

ifステートメントの真のパスも偽のパスも取得されなかったため、割り当てに失敗すると、ステートメント全体の実行が停止しました。POSIXモードのbashと割り当てが失敗した場合、ksh93とzshはすべてスクリプトを中止します。

これについてPOSIX標準を引用すると:

コマンド名を含まないがコマンド置換を含むコマンドには、シェルが実行した最後のコマンド置換の終了ステータスがあります。

これは正確に含まれるシェル文法の一部です

 foo=$(err 42)

これはsimple_command(simple_command→cmd_prefix→ASSIGNMENT_WORD)から来ています。したがって、割り当てが成功した場合、コマンドの置換が関係していない限り、終了ステータスはゼロです。その場合、終了ステータスは最後のステータスです。割り当てが失敗すると、終了ステータスはゼロ以外になりますが、キャッチできない場合があります。


1
あなたの答えに追加するために、これはこれに関する新しいPOSIX標準が引用されている別のスレッドからの答えです。結論は基本的に同じです:unix.stackexchange.com/a/270831/117599
phk

4

あなたは言う、

...割り当て自体がコマンドとしてカウントされるように見えます...終了値がゼロですが、割り当ての右側の前に適用されます(たとえば、コマンド置換呼び出し...)

それはひどい見方ではありません。しかし、それは少し単純化しすぎです。からの全体的な返品ステータス

A = $(cmd 1)B = $(cmd 2)C = $(cmd 3)D = $(cmd 4)E = mc 2
からの終了ステータスです。後に発生した割り当て割り当ては0に全体的な終了ステータスを設定しません。cmd4E=D=

また、icarusが 指摘しているように、変数は読み取り専用として設定できます。icarusの例について、次のバリエーションを考えてみます。

$ err() { echo "stdout $*"; echo "stderr $*" >&2; return ${1:-1}; }
$ readonly A
$ Z=$(err 41 zebra) A=$(err 42 antelope) B=$(err 43 badger)
stderr 41 zebra
stderr 42 antelope
bash: A: readonly variable
$ echo $?
1
$ printf "%s = %s\n" Z "$Z" A "$A" B "$B"
Z = stdout 41 zebra
A =
B =
$

にもかかわらず、A読み取り専用で、bashが右側にコマンド置換を実行しA=-そして、次にため、コマンドを中止しますA読み取り専用です。これは、割り当ての終了値が割り当ての右側の前に適用されるというあなたの解釈とさらに矛盾します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.