Làm thế nào bạn có thể chạy một lệnh trong bash over cho đến khi thành công


236

Tôi có một tập lệnh và muốn hỏi người dùng một số thông tin, tập lệnh không thể tiếp tục cho đến khi người dùng điền thông tin này. Sau đây là nỗ lực của tôi trong việc đưa một lệnh vào một vòng lặp để đạt được điều này nhưng nó không hoạt động vì một số lý do.

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

Tôi đã thử nhiều biến thể của vòng lặp while:

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

Nhưng tôi dường như không thể làm cho nó hoạt động.

Câu trả lời:


403
until passwd
do
  echo "Try again"
done

hoặc là

while ! passwd
do
  echo "Try again"
done

20
Khó để Ctrl-C ra khỏi đây.
DonGar

Nếu bạn nghĩ rằng bạn sẽ cần phải hủy cái này, chỉ cần mở một phiên bản mới của shell của bạn (ví dụ: gõ "bash") và, khi bạn muốn hủy nó, hãy vào một cửa sổ terminal khác và giết bash mới được sinh ra quá trình.
Ethan

50
Dễ dàng để Ctr-C thoát khỏi điều này: until passwd; do echo "Try again"; sleep 2; done- tất cả những gì bạn phải làm là nhấn Ctr-C ngay sau đó (trong vòng hai giây đã cho) echocông việc đã làm.
Christian

9
@azmeuk: Hãy thử một cái gì đó như until passwd || (( count++ >= 5 )); do echo "foo"; done(chỉ bash, đảm bảo đặt số là 0 nếu biến đổi đó tồn tại) Nếu bạn cần điều này cho sh đơn giản, hãy tăng bộ đếm trong cơ thể và sử dụng []
Justin Sane

2
Sau khi tham khảo trang này nhiều lần, tôi quyết định tạo một hàm bash chung để thử lại các lệnh, đây là: gist.github.com/felipou/6fbec22c4e04d3adfae5
felipou 14/2/2016

93

Bạn cần kiểm tra $?thay vào đó là trạng thái thoát của lệnh trước đó. passwdthoát bằng 0 nếu mọi thứ đều ổn, và khác không nếu thay đổi mật khẩu không thành công (sai mật khẩu, sai mật khẩu, v.v ...)

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

Với phiên bản backtick của bạn, bạn đang so sánh đầu ra của passwd, đó sẽ là những thứ giống Enter passwordconfirm passwordtương tự.


2
Có nên như $?vậy không?
Shawn Chin

Tôi thích điều này bởi vì nó rõ ràng làm thế nào để thích ứng với tình huống ngược lại. ví dụ: chạy chương trình có lỗi không xác định cho đến khi không thành công
Eric

Khi thành công được biểu thị bằng mã thoát khác không, đây là thứ bạn cần.
Gudlaugur Egilsson

2
Tôi nghĩ rằng đây có thể được cải thiện đôi chút khi bằng cách thay đổi đầu tiên passwdvới /bin/falsenếu bạn có một số dài và lệnh phức tạp mà bạn không muốn giữ lại hai phiên bản.
coladict

Nên là câu trả lời imho. Điều này sẽ hoạt động trong hầu hết các shell (được thử nghiệm trong bash, mksh và tro) và dễ dàng thích nghi với tình huống.
linuxandria

72

Để giải thích về câu trả lời của @Marc B,

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

Là cách tốt để làm điều tương tự mà không phải là lệnh cụ thể.


11
Thật không may cho tôi không may (tôi không tìm thấy lệnh '!!'). Làm thế nào là nó phải làm việc?
Julian Rudolph

2
Đó là một mẹo bash để chạy lệnh trước đó. Ví dụ: nếu bạn quên viết sudotrước lệnh, bạn chỉ cần thực hiện sudo !!để chạy lệnh trước đó với quyền root.
JohnEye

1
Tôi có thể tạo một tập lệnh trong hồ sơ của mình để có thể làm điều này không, vì vậy tôi có thể đi: $ makelastwork
user230910

2
Làm thế nào để ngủ giữa các lần chạy?
Kamil Dziedzic

6

Bạn có thể sử dụng một vòng lặp vô hạn để đạt được điều này:

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

2
Đây là câu trả lời duy nhất không yêu cầu đưa lệnh đa dòng của tôi vào một hàm. Tôi đã làm && breaksau lệnh xác minh của tôi mặc dù thay vì trường hợp chọn.
carlin.scott

4

Nếu bất cứ ai muốn có giới hạn thử lại:

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)về cơ bản là luôn luôn sai. Sử dụng until commandthay thế. Các $(...)nguyên nhân đầu ra của commandđể là chính mình chạy như một lệnh, và trạng thái thoát của rằng lệnh thứ cấp là những gì các vòng quyết định để chạy hoặc thất bại trên; nó chỉ nếu có không có stdout rằng trạng thái thoát của lệnh tự nó được xem xét khi lệnh thay thế là hiện tại.
Charles Duffy

$commandcũng không phải là một trình giữ chỗ tuyệt vời - hãy xem BashFAQ # 50 về lý do tại sao sử dụng chuỗi để lưu trữ các lệnh là không đáng tin cậy. Tuy nhiên, điều này là tốt hơn so với nó; downvote rút lại.
Charles Duffy

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

3
Đây không phải là cách để làm điều đó ... bạn đang phủ nhận sự xuất sắc của psswd và sau đó thực hiện một bài kiểm tra đơn nhất về nó. @duckworthd là tốt.
Ray Foss

Hơn nữa, vì không có trích dẫn, kiểm tra sẽ misbehave khi có đầu ra nhưng đó là nhiều hơn một từ, hoặc là một biểu glob rằng trận đấu tập tin trong thư mục hiện hành, hoặc vân vân.
Charles Duffy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.