Bagaimana Anda bisa menjalankan perintah dalam bash over hingga sukses


237

Saya memiliki skrip dan ingin meminta informasi kepada pengguna, skrip tidak dapat dilanjutkan sampai pengguna mengisi informasi ini. Berikut ini adalah upaya saya untuk menempatkan perintah dalam satu lingkaran untuk mencapai ini tetapi tidak berhasil karena suatu alasan.

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

Saya telah mencoba banyak variasi loop sementara:

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

Tapi sepertinya saya tidak bisa membuatnya bekerja.

Jawaban:


403
until passwd
do
  echo "Try again"
done

atau

while ! passwd
do
  echo "Try again"
done

20
Sulit untuk Ctrl-C keluar dari ini.
DonGar

Jika Anda merasa perlu membatalkan ini, cukup buka instance baru dari shell Anda (contoh, ketik "bash") dan, ketika Anda ingin membatalkannya, masuk ke jendela terminal lain dan bunuh bash yang baru saja muncul proses.
Ethan

50
Mudah untuk Ctr-C dari ini: until passwd; do echo "Try again"; sleep 2; done- yang harus Anda lakukan adalah tekan Ctr-C tepat setelah (dalam dua detik diberikan) yang echomelakukan pekerjaan itu.
Christian

9
@azmeuk: Coba sesuatu seperti until passwd || (( count++ >= 5 )); do echo "foo"; done(hanya bash, pastikan untuk menetapkan hitungan ke 0 jika itu tidak ada). Jika Anda membutuhkan ini untuk sh polos, tambahkan penghitung di tubuh dan gunakan []
Justin Sane

2
Setelah merujuk ke halaman ini berkali-kali, saya memutuskan untuk membuat fungsi bash generik untuk mencoba kembali perintah, ini dia: gist.github.com/felipou/6fbec22c4e04d3adfae5
felipou

94

Anda perlu menguji $?sebagai gantinya, yang merupakan status keluar dari perintah sebelumnya. passwdkeluar dengan 0 jika semuanya berfungsi dengan baik, dan bukan nol jika perubahan passwd gagal (kata sandi salah, kata sandi salah, dll ...)

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

Dengan versi backtick Anda, Anda membandingkan output passwd, yang akan berupa hal-hal seperti Enter passworddan confirm passworddan sejenisnya.


2
Bukankah seharusnya begitu $??
Shawn Chin

Saya suka ini karena jelas bagaimana mengadaptasinya untuk situasi yang berlawanan. mis. jalankan program dengan bug non-deterministik sampai gagal
Eric

Ketika kesuksesan ditunjukkan oleh kode keluar yang bukan nol, inilah yang Anda butuhkan.
Gudlaugur Egilsson

2
Saya pikir ini bisa sedikit ditingkatkan dengan mengubah dulu passwddengan /bin/falsejika Anda memiliki beberapa perintah yang panjang dan rumit yang Anda tidak ingin menyimpan dua versi.
coladict

Seharusnya jawaban yang diterima imho. Ini harus bekerja di sebagian besar cangkang (diuji dalam bash, mksh, dan abu) dan mudah beradaptasi dengan situasi.
linuxandria

73

Untuk menguraikan jawaban @Marc B,

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

Adalah cara yang baik untuk melakukan hal yang sama yang tidak spesifik perintah.


11
Sayangnya tidak berfungsi untuk saya (perintah "!!" tidak ditemukan). Bagaimana cara kerjanya?
Johannes Rudolph

2
Ini adalah trik bash untuk menjalankan perintah sebelumnya. Sebagai contoh jika Anda lupa menulis sudodi depan perintah, Anda bisa melakukannya sudo !!untuk menjalankan perintah sebelumnya dengan hak akses root.
JohnEye

1
dapatkah saya membuat skrip di profil saya yang dapat melakukan ini, jadi saya dapat membuka: $ makelastwork
user230910

2
Bagaimana cara tidur antar lari?
Kamil Dziedzic

6

Anda dapat menggunakan loop tak terbatas untuk mencapai ini:

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

2
Ini adalah satu-satunya jawaban yang tidak memerlukan menempatkan perintah multi-line saya dalam suatu fungsi. Saya lakukan && breaksetelah perintah verifikasi saya alih-alih kasus pilih.
carlin.scott

4

Jika ada yang ingin mencoba lagi:

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)pada dasarnya selalu salah. Gunakan until commandsebagai gantinya. The $(...)menyebabkan keluaran dari commandmenjadi dirinya sendiri dijalankan sebagai perintah, dan status keluar dari bahwa perintah sekunder menjadi apa loop memutuskan untuk menjalankan atau gagal pada; itu hanya jika ada adalah tidak ada stdout bahwa status keluar dari perintah itu sendiri dianggap ketika substitusi perintah hadir.
Charles Duffy

$commandjuga bukan pengganti yang bagus - lihat BashFAQ # 50 tentang mengapa menggunakan string untuk menyimpan perintah secara bawaan tidak dapat diandalkan. Namun, ini lebih baik daripada sebelumnya; downvote ditarik.
Charles Duffy

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

3
Ini bukan cara untuk melakukannya ... Anda meniadakan stdout psswd dan kemudian melakukan tes unary. @ sialworthd baik.
Ray Foss

Selain itu, karena tidak ada mengutip, tes ini akan berkelakuan ketika ada adalah output tetapi itu lebih dari satu kata, atau ekspresi glob bahwa file pertandingan di direktori saat ini, atau lain sebagainya.
Charles Duffy
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.