テスト後に最後の終了ステータスを維持する方法


8

$?テスト後に最後のコマンドの終了ステータス()を変更しないでおくことは可能ですか?

例えば、私はしたいと思います:

command -p sudo ...
[ $? -ne 1 ] && exit $?

最後exit $?はsudo終了ステータスを返す必要がありますが、代わりに常に0(テストの終了コード)を返します。

一時変数なしでそれを行うことは可能ですか?

さらに明確にする別の例:

 spd-say "$@"
 [ $? -ne 127 ] && exit $?

この場合、最初のコマンドが見つかった場合にのみ終了します(終了コード!= 127)。そして、私は実際のspd-say終了コードで終了したいです(それはそうではないかもしれません 0)。

編集:私は、移植性を高めるためにPOSIX準拠のソリューションを好むことを忘れていました。

同じコマンドの代替手段を提供したいスクリプトでこの構成を使用します。たとえば、私のcrc32スクリプトを参照してください。

一時変数の問題は、他の変数を隠してしまう可能性があり、長い名前を使用しなければならないことを回避することです。


いいえ、しかし、あなたはif ! command -p sudo; then exit; fiあなたの例で同じ結果になるだろうことをすることができます。
ヨルダン2015年

代わりに、127コードをテストする場合はどうなりますか?(例[ $? -ne 127 ] && exit $?
eadmaster 2015年

1
@jordanm:ほんと?OPが意図したコード/ロジックを提示していて、私がそれを正しく読んでいる場合、sudoコマンドが成功した場合(つまり、sudoステータス0で終了する場合)にスクリプトを終了する必要があります。しかし、あなたのコードでは、成功した場合、スクリプトは実行を継続します(終了しません)sudo
G-Manは 'Reinstate Monica'

@ G-Man-質問者の状態は実際にはまったくのリターンに基づいておりcommand、まったくsudoではないことにかなり確信しています。が何を意味するかそれの私が(!終了コードを= 127)最初のコマンドが見つかった場合にのみ終了したいとあるために指定された戻りcommand、それが起動するコマンドが見つからない場合。問題はsudo、テストの一部として呼び出すことで、最初からのsudoリターンを押しつぶして、テストをゆがめることができることだと思いcommandます。
mikeserv 2015年

回答:


3

$_で動作します(少なくとも)インタラクティブdashbashzshksh (ただし、明らかではない条件文で要求されるように)mkshシェル。それらのうち-私の知る限り-だけでbashありzsh、スクリプト化されたシェルにデータを追加します。これはPOSIXパラメータではありませんが、最新の対話型シェルにはかなり移植可能です。

よりポータブルなソリューションについては、次のことができます。

command -p sudo ...
eval '[ "$?" = 127 ] || exit '"$?"

これにより、基本的にの初期値を$?スクリプトの末尾に展開してから、その値を先頭でテストすることもできます。

とにかく、あなたはコマンドsudoがシェルの組み込みの-p ポータブルパス文字列でコマンドを見つけることができるかどうかをテストしているように見えるので、あなたcommandはそれをもっと直接見ることができると思います。また、単に、明確にすることがcommand ないであろういずれかの場所を調べる引数sudoそれが唯一であるので- sudo-と何もそれが呼び出していない-その戻り値に関連しています。

とにかく、それがあなたがやろうとしていることなら:

command -pv sudo >/dev/null || handle_it
command -p  sudo something or another

...コマンドsudo実行でエラーが発生する可能性がなく、テストの結果を歪めるような方法でテストとしてうまく機能します。


9

実際の要件に応じて、オーバーヘッドなしで確実に終了ステータスを処理するためのさまざまなオプションがあります。

変数を使用して終了ステータスを保存できます。

command -p sudo ...
rc=$?
[ "$rc" -ne 1 ] && echo "$rc"

成功または失敗を直接確認できます。

if  command -p sudo ...
then  echo success
else  echo failure
fi

または、case構成を使用して終了ステータスを区別します。

command -p sudo ...
case $? in
(1) ... ;;
(127) ... ;;
(*) echo $? ;;
esac

質問で尋ねられた特別なケースで:

command -p sudo ...
case $? in (1) :;; (*) echo $?;; esac

これらすべてのオプションには、POSIX標準に準拠しているという利点があります。

(注:echo上記のコマンドを使用して説明exitするために、要求された機能に一致する適切なステートメントに置き換えます。)


コメントは詳細な議論のためのものではありません。この会話はチャットに移動しました
terdon

1
(最後のコメントがチャットに移動しなかったのはなぜだろうと思います。)-既にチャットで説明され、POSIXの引用によって裏付けられています(詳細はそこを参照)。1.)("$(get_errnos)")コマンド置換の人工的な追加であり、実際のエラーコードとの比較が質問で求められます。2)標準で何が変更$?されるか(したがって何が変更されないか)が明確であり、3。)そこにあるその構成には副作用はありません(そうした場合を除き、不必要に導入しない限り)。-OTOH、あなたが気にするので、あなたが好む他の答えは明らかに非標準です。
Janis

1
@mikeserv; それは迷惑なんだ(と誤解を招く!)だけでなく、あなたが適用されますので、ダブルスタンダードを!同じ人工$(get_errnos)コードを他のソリューション(( exit 42 ); test "$(get_errnos)" -ne $? && echo $_)に適用すると、それらも機能しません。(あなたは私の標準的なソリューションを他の非標準的なハックではなく、誤解を招くように好んだ。)-もちろん答えに任意のコードを追加してそれを台無しにすることができる。-およびWRTの変更$?。見つけられないからといって、それが真実ではないという意味ではありません。(私は、POSIXで検索するためのキーワードも含めて、既にディスカッションで提供しています。)
Janis

1
@mikeserv; しかし、これもまた、(実りのない、果てしない)議論を続ける傾向があります。@ terdonが正しく観察されたため、ここでは説明しないでください。
Janis

1
@mikeserv; あなたが最初に言及した最初にzsh(最初に言及しましたが、後で追加しましたdash)冒頭で、POSIX caseで終了ステータスと設定が$?適切に定義されているように見えるので、これはバグだと思います。-そしてここでも、あなたは二重の基準を適用します。他のハックは、例えば、標準ではなく、他の標準シェル(例えばksh)では確実に機能しません。-私の提案は標準であり、bash(主にLinuxで使用されています)およびksh(商用Unixの主流のシェル)で機能します。
Janis

7
command -p ...
test 1 -ne $? && exit $_

を使用する$_と、前のコマンドの最後の引数に展開されます。


1
この特定の例に有効ですが、$?$_参照の間に他のコマンドがない場合にのみ使用できます。私見では、他の場合でも機能する一貫した方法を使用することをお勧めします(コードの読みやすさにも役立ちます)。
Dan Cornilescu 2015年

4
シェルは具体的には2回指定されています。1回はタイトルで、もう1回はタグです。移植性についても質問のどこにも触れられていなかったため、上記のシェルで機能する答えを示しました。他にどんな奇妙な制限が作られるのでしょうか?
llua

1
@mikeserv; あなたがそれを逃した場合に備えて:私は言った:「POSIXに関してここに非常に最初のコメントがありました。」修正する必要がありました。それ以上でもそれ以下でもありません。-あなたと徹底的に議論され、そこで説明されているように、他の回答の3つの提案はすべてPOSIXによって明確に定義されています。ここであなたの(IMOが間違っている)意見を繰り返す必要はなく、紛争の別の反復を開始する必要もありません。
Janis

1
@mikeserv; case パターンでの展開の副作用は、理論的には重要な唯一の場所ですが(与えられた質問では重要ではありません)、構築されたケースです。-いずれの場合でも、シェルコマンドの置換により、埋め込みコマンドの結果x=${a!b}が反映されます。通常、エラーを引き起こす可能性のあるコマンドがない場合は、他の展開が戻り状態に影響を与えません(気になる場合は、ここでは関係ありません)。- 「コマンド名のないコマンド」とはどういう意味ですか?
Janis

1
@mikeserv; 不要なコードを作成したアドホックでのみ破壊できます。人工的なナンセンスを不必要に導入せずに提案をすれば、完全に灰色の領域はありません。この場合の要件は完全に明確でした。1。コマンドを実行する、2。終了コードを確認する、3。終了コードを返す。-分かりますか?-あなたはその要件を任意に変更して、議論を構成しました。
Janis

6

シェル関数を定義(および使用)できます。

check_exit_status()
{
    [ "$1" -ne 1 ] && exit "$1"
}

その後

command -p sudo ...
check_exit_status "$?"

それはのコピーを作成しますので、間違いなく、これは、「不正行為」である$?check_exit_status引数リスト。

これは少し厄介に見えるかもしれませんが、そうです。(これは、問題に任意の制約を課すと発生することがあります。)これは柔軟性がないように見えるかもしれませんが、そうではありません。check_exit_statusより複雑にして、終了ステータス値で実行するテストを指示する引数を追加できます。


0

直接的な質問に答えるには、いいえ、$?変更しないでおくことはできません。そして、これは私があなたが間違った問題に焦点を合わせているのではないかと疑うケースの1つです。一時変数は、探している効果を得るための標準的で好ましい方法です。それは非常に標準的であるので、使用したくない理由があると思う理由があれば、それを放棄(または再考)することをお勧めします。他の方法で追加された余分な複雑さの価値があると私は強く疑います。

単に好奇心を求めているだけなら、答えはノーです。


@mikeservよくわかりません-手動で割り当てる$?などのことですか?
David Z

0

現在のスクリプト/シェルを終了せずに以前の終了ステータスを保持するためのコードスニペットを次に示します

EXIT_STATUS=1
if [[ $EXIT_STATUS == 0 ]]
then
  echo yes
else
  (exit $EXIT_STATUS)
fi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.