成功するまでbashでコマンドを実行するにはどうすればよいですか


237

スクリプトがあり、ユーザーにいくつかの情報を要求したいのですが、ユーザーがこの情報を入力するまでスクリプトは続行できません。以下は、これを達成するためにループにコマンドを入れようとする私の試みですが、何らかの理由で機能しません。

echo "Please change password"
while passwd
do
echo "Try again"
done

whileループの多くのバリエーションを試しました:

while `passwd`
while [[ "`passwd`" -gt 0 ]]
while [ `passwd` -ne 0 ]]
# ... And much more

しかし、私はそれを機能させることができないようです。

回答:


403
until passwd
do
  echo "Try again"
done

または

while ! passwd
do
  echo "Try again"
done

20
このうちCtrl-Cは難しい。
DonGar 2013

これをキャンセルする必要があると思われる場合は、シェルの新しいインスタンス(例:「bash」と入力)を開き、キャンセルする場合は別のターミナルウィンドウに移動して、新しく生成されたbashを終了します。処理する。
イーサン

50
この中から簡単にCtr-Cを:until passwd; do echo "Try again"; sleep 2; done-あなたがしなければならないのは、echoそれが仕事をした直後(与えられた2秒以内)にCtr-Cを押すことだけです。
クリスチャン

9
@azmeuk:のようなトライ何かuntil passwd || (( count++ >= 5 )); do echo "foo"; done(bashののみ、そのvaraibleが存在する場合は0に設定されたカウントに確認してください)あなたは無地のshのためにこれが必要な場合は、身体および使用中のカウンタをインクリメント[]
ジャスティン・サン

2
このページを何度も参照した後、コマンドを再試行するための一般的なbash関数を作成することにしました。これは次のとおり
felipou

94

$?代わりにテストする必要があります。これは、前のコマンドの終了ステータスです。passwdすべてが正常に機能した場合は0で終了し、passwdの変更が失敗した場合(パスワードの誤り、パスワードの不一致など)はゼロ以外で終了します。

passwd
while [ $? -ne 0 ]; do
    passwd
done

あなたのバッククォートバージョンでは、次のようなものだろうpasswdのの出力、比較しているEnter passwordと、confirm password等が挙げられます。


2
そうじゃないの$?
Shawn Chin

反対の状況にどのように適応するかが明らかなので、私はこれが好きです。たとえば、失敗するまで非決定論的なバグを含むプログラムを実行する
Eric

成功がゼロ以外の終了コードで示される場合、これが必要です。
Gudlaugur Egilsson 2017

2
2つのバージョンを保持したくない長く複雑なコマンドがある場合は、最初のpasswdを変更することで、これを少し改善できると思います/bin/false
coladict

受け入れられた答えであるはずです。これはほとんどのシェル(bash、mksh、ashでテスト済み)で機能し、状況に簡単に適応できます。
linuxandria

73

@Marc Bの答えを詳しく説明するには、

$ passwd
$ while [ $? -ne 0 ]; do !!; done

コマンド固有ではない同じことをする良い方法です。


11
残念ながら機能しません( '!!'コマンドが見つかりません)。それはどのように機能するはずですか?
ヨハネスルドルフ

2
前のコマンドを実行するのはbashトリックです。たとえばsudo、コマンドの前に書き込むのを忘れた場合はsudo !!、前のコマンドをroot権限で実行するだけです。
JohnEye

1
$ makelastwork:私は行くことができますので、これを行うことができ、私のプロファイルでスクリプトすることができます
user230910

2
実行と実行の間にスリープする方法は?
Kamil Dziedzic 2017年

6

あなたはこれを達成するために無限ループを使うことができます:

while true
do
  read -p "Enter password" passwd
  case "$passwd" in
    <some good condition> ) break;;
  esac
done

2
これは、複数行コマンドを関数に入れる必要がなかった唯一の答えです。&& breakselectケースではなく、検証コマンドの後に実行しました。
carlin.scott

4

再試行制限を希望する場合:

max_retry=5
counter=0
until $command
do
   sleep 1
   [[ counter -eq $max_retry ]] && echo "Failed!" && exit 1
   echo "Trying again. Try #$counter"
   ((counter++))
done

1
until $(command)基本的に常に間違っています。until command代わりに使用してください。$(...)原因出力のをcommand自身がコマンドとして実行する、との終了ステータスその二次のコマンドは、ループが実行または上に失敗することを決定するものであること。コマンド置換が存在するときにコマンド自体の終了ステータスが考慮されるの、標準出力ない場合のみです。
Charles Duffy

$commandも素晴らしいプレースホルダーではありません- コマンドを保存するために文字列を使用することが本質的に信頼できない理由については、BashFAQ#50を参照してください。それでも、これは以前よりも優れています。反対投票が撤回されました。
Charles Duffy

3
while [ -n $(passwd) ]; do
        echo "Try again";
done;

3
これはそれを行う方法ではありません... psswdのstdoutを無効にし、それに対して単項テストを行っています。@duckworthdは良いです。
レイフォス

さらに、引用符がないため、出力があるテストは正しく動作しませんが、1ワードを超えるか、現在のディレクトリ内のファイルと一致するglob式などになります。
Charles Duffy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.