インライン実行エラー時にbashブレークコマンドを作成する方法

インライン実行エラー時にbashブレークコマンドを作成する方法

Bashのコマンド置換(またはインライン実行と呼ばれるもの)を使用すると、基本$()コマンドが実行される前にテキストが返されることがあります。 $() がエラーコードを返す場合、基本コマンドを中断する方法

具体的には、セカンダリインライン実行の試みを停止/防止したいと思います。

Echo $(ls /devb/*) is better than $(ls /dev/*)

つまり、 "ls /devb/"がゼロ以外の終了コードを返す場合は、/ devリストを実行したくありません。

私の実際の例はかなり長く、具体的な詳細は質問にとってそれほど重要ではありませんが、単純化されたバージョンは次のとおりです。

Connect_to_foreign_system 1.1.1.1 /u:$(zenity <prompt for user>) /p:$(zenity <prompt for password>)

ユーザープロンプトがキャンセルされると、zenityは終了コード1を返しますが、デフォルトのコマンドは続行され、次にパスワードの入力を求めます。

最初にエラーメッセージが表示され、パスワードの入力を求められたくない場合は、Connect_to_foreign_systemを実行しないことをお勧めします。

set -eスクリプトで実行するものではありません。これは純粋なコマンドラインですが、2番目のインラインコマンドと基本コマンドを含むスクリプトに入れても引き続き実行されます。

各テキスト文字列を取得し、コマンドを実行して終了コードをテストするスクリプトを書くことができることを知っています。スタンドアロンステートメントでこれを行う方法を尋ねています。

答え1

私はそれをします:

cmd1_output=$(cmd1) && cmd2_output=$(cmd2) &&
  printf '%s\n' "Both cmd1 and cmd2 succeeded and their output was respectively $cmd1_output and $cmd2_output"

あなたの場合は次のとおりです。

user=$(zenity <prompt for user>) &&
  password=$(zenity <prompt for password>) &&
  Connect_to_foreign_system 1.1.1.1 /u:"$user" /p:"$password"

$(...)上記のsはスカラー変数の割り当てに使用されるため、bashで引用する必要はありませんが、上記のように引用符が$userない$password場合は分割+globの影響を受けるため、コマンド引数で使用するときに引用する必要があります。

通常、コマンドラインパラメータは通常システム内で公開されるため(ps -Afたとえば、出力に表示される)、コマンドラインからパスワードを渡すのは非常に悪い習慣です。ほとんどのコマンドには、通常、環境変数または一部のファイルまたはファイル記述子を介して秘密を渡すより安全な方法があります。

$user一度だけ使用される変数と変数で変数名前空間を汚染したくない場合は、$passwordサブシェル()で完全なand-listを実行できます(...)

(user=$(zenity <prompt for user>) &&
  password=$(zenity <prompt for password>) &&
  Connect_to_foreign_system 1.1.1.1 /u:"$user" /p:"$password")

または、bashからzshに切り替えるオプションがある場合は、変数の代わりに匿名関数の位置引数を使用できます。

() {
  1=$(zenity <prompt for user>) &&
    2=$(zenity <prompt for password>) &&
    Connect_to_foreign_system 1.1.1.1 /u:$1 /p:$2
}

(zshでは、Split + globは引用符なしの引数に対して暗黙の拡張を実行しないため、$1/を引用符で囲む必要はありません。)$2


cmd2失敗時に実行せずにksh93、zsh、bashを含むがdash、busybox sh、yash、またはmkshを含まない一部のシェルでcmd1出力を引き続き使用するには、次の手順を実行できます。cmd1

printf '%s\n' "output of cmd1: $(cmd1) and of cmd2 (not run if cmd1 failed) $([ "$?" -eq 0 ] && cmd2)"

答え2

このようなインライン実行をコマンド置換と呼びます。コマンドの終了状態を確認するには、他のコマンドなしでコマンドにそのコマンドを入れる必要があり、出力をキャプチャするための割り当てだけが必要です。たとえば、

if a=$(foo); then
    echo >&2 "first command failed, exiting"
    exit 1
fi
b=$(bar)
echo "output of first command: '$a', output of second: '$b'"

シェルはglobを拡張し、シェルが提供するファイル名のみを印刷するため、これは$(ls /dev/*)少し愚かです。 (他の情報を使用または取得するために使用しない限り)、globと一致するすべてのサブディレクトリの内容が一覧表示されます。それにもかかわらず、このような問題は再び考える価値があります。最初のレベルのコンテンツのみを希望する場合は、代わりにまたはを使用してください。/dev/*ls-l-Fls/devls /devecho /dev/*

関連情報