web-dev-qa-db-ja.com

コマンド置換内に設定されたアクセス変数

簡単なスクリプトを書きました

 #!/bin/bash -x
 selentry=`ls -l / | sort ; ts=${PIPESTATUS[0]}`
 echo $ts

しかし、$ tsは何も表示しません。 $ ts変数を表示するにはどうすればよいですか、または変数のコマンドから終了ステータスコードを取得するにはどうすればよいですか?

selentry=`ls -l / | sort`
4
DeadKenny

に:

selentry=`ls -l / | sort ; ts=${PIPESTATUS[0]}`

より現代的なものと同じ:

selentry=$(ls -l / | sort ; ts=${PIPESTATUS[0]})

$(...)内のコードは、サブシェル環境で実行されます(bashおよびksh93以外のシェルの場合、別のシェルプロセスでも実行されます)。したがって、そのサブシェル内の変数に加えられた変更は、親シェルには影響しません。

あなたがするとき:

var=$(cmd)

ただし、cmdの終了ステータスは$?で利用可能になります。これは$PIPESTATUSには適用されません。次の場合:

var=$(foo | bar)

含まれる値は1つだけです(サブシェルの終了コード。ここではbarの終了ステータスになります(pipefailオプションがオンになっている場合は、fooがゼロ以外の場合)。$pipestatus配列が割り当てコマンドの影響を受けないzshではさらに悪化します。

ただし、ここで、(サブシェルの)sortの終了ステータスを気にしない場合は、次のことができます。

selentry=$(ls -l / | sort; exit "${PIPESTATUS[0]}")
ts=$?

ここでは、次のこともできます。

exec 3< <(ls -l /) # here ls is started as an asynchronous command
ls_pid=$!
selentry=$(sort <&3)
sort_status=$?
wait "$ls_pid"
exec 3<&- # close that fd 3
ls_status=$?

あるいは:

{
  selentry=$(sort)
  sort_status=$?
  wait "$!"
  ls_status=$?
} < <(ls -l /)

変数割り当てをコマンド置換後も存続させるというより一般的な質問では、ksh93で、${ cmd;}形式のコマンド置換を使用できます(ただし、ksh93$PIPESTATUS/$pipestatusをサポートしていません)。

var=${
  foo; c1=$?
  bar; c2=$?
}

他のBourneのようなシェルには同等のものはありません。一時ファイルなど、他の手段を介してデータを渡す必要があります。

var=$(
  foo; echo "c1=$?" > "$tempfile"
  bar; echo "c2=$?" >> "$tempfile"
)
. "$tempfile"

またはここ:

selentry=$(
  ls -l / | sort
  typeset -p PIPESTATUS | sed '1s/PIPESTATUS/my_&/' > "$tempfile"
}
. "$tempfile"
ls_status=${my_PIPESTATUS[0]}
5