Jak uruchomić polecenie w mgnieniu oka aż do sukcesu?


237

Mam skrypt i chcę zapytać użytkownika o pewne informacje, skrypt nie może być kontynuowany, dopóki użytkownik nie wypełni tych informacji. Oto moja próba umieszczenia polecenia w pętli, aby to osiągnąć, ale z jakiegoś powodu to nie działa.

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

Próbowałem wielu odmian pętli while:

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

Ale nie mogę sprawić, żeby zadziałało.

Odpowiedzi:


403
until passwd
do
  echo "Try again"
done

lub

while ! passwd
do
  echo "Try again"
done

20
Trudne z tego Ctrl-C.
— DonGar,

Jeśli uważasz, że będziesz musiał to anulować, po prostu otwórz nową instancję swojej powłoki (na przykład wpisz „bash”), a kiedy chcesz ją anulować, przejdź do innego okna terminala i zabij nowo spawnowaną bash proces.
— Ethan

50
Łatwy do Ctr-C z tego: until passwd; do echo "Try again"; sleep 2; done- wszystko co musisz zrobić, to nacisnąć Ctr-C zaraz po (w podanych dwóch sekundach), czy echowykonał swoją pracę.
— Christian

9
@azmeuk: Spróbuj czegoś takiego until passwd || (( count++ >= 5 )); do echo "foo"; done(tylko bash, upewnij się, że ustawiłeś count na 0, jeśli ta zmienna istnieje) Jeśli potrzebujesz tego dla zwykłego sh, zwiększ licznik w ciele i użyj []
— Justin Sane

2
Po wielokrotnym odwoływaniu się do tej strony postanowiłem utworzyć ogólną funkcję bash, aby ponowić polecenia, oto ona: gist.github.com/felipou/6fbec22c4e04d3adfae5
— felipou

94

Zamiast tego musisz przetestować $?, co stanowi status wyjścia poprzedniego polecenia. passwdkończy się na 0, jeśli wszystko działało poprawnie, i niezerowym, jeśli zmiana hasła nie powiodła się (nieprawidłowe hasło, niedopasowanie hasła itp.)

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

W swojej wersji backtick porównujesz dane wyjściowe passwd, które byłyby podobne Enter passwordi confirm passwordpodobne.


2
Czy nie powinno tak być $??
— Shawn Chin,

Podoba mi się to, ponieważ jest jasne, jak dostosować go do przeciwnej sytuacji. np. uruchom program z niedeterministycznym błędem, dopóki nie zawiedzie
— Eric

Gdy sukces jest wskazywany przez niezerowy kod wyjścia, właśnie tego potrzebujesz.
— Gudlaugur Egilsson

2
Myślę, że to może być nieco poprawić zmieniając pierwszą passwdze /bin/falsejeśli masz jakieś długie i skomplikowane polecenia, które nie chcą, aby dwie wersje.
— coladict

Powinna być przyjęta odpowiedź imho. Powinno to działać w większości powłok (testowane w bash, mksh i ash) i można je łatwo dostosować do sytuacji.
— linuxandria

73

Aby rozwinąć odpowiedź na @Marc B,

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

To dobry sposób na zrobienie tego samego, co nie jest specyficzne dla komendy.


11
Niestety nie działa (otrzymuję polecenie „!!”). Jak to ma działać?
— Johannes Rudolph,

2
Uruchomienie poprzedniego polecenia jest bashową sztuczką. Na przykład, jeśli zapomnisz napisać sudoprzed poleceniem, możesz po prostu sudo !!uruchomić poprzednie polecenie z uprawnieniami administratora.
— JohnEye,

1
czy mogę zrobić skrypt w moim profilu, który może to zrobić, więc mogę przejść: $ makelastwork
— user230910 24.04.2016

2
Jak spać między biegami?
— Kamil Dziedzic

6

Aby to osiągnąć, możesz użyć nieskończonej pętli:

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

2
To jedyna odpowiedź, która nie wymagała umieszczenia mojego polecenia wieloliniowego w funkcji. Zrobiłem to && breakpo poleceniu weryfikacji zamiast wyboru przypadku.
— carlin.scott 27.04.2018

4

Jeśli ktoś chce mieć limit ponownych prób:

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)jest w zasadzie zawsze źle. Użyj until commandzamiast tego. $(...)Powoduje wyjście z commandsię sam uruchomić jako polecenie, a stan wyjścia tego polecenia wtórnym być co pętla zdecyduje się uruchomić lub nie na temat; to tylko wtedy, gdy jest nie stdout, że stan wyjścia samego polecenia jest uważany gdy substytucja komenda jest obecny.
— Charles Duffy

$commandnie jest też wielkim symbolem zastępczym - zobacz BashFAQ # 50, dlaczego używanie ciągów do przechowywania poleceń jest wewnętrznie zawodne. Mimo to jest to lepsze niż było; wycofano głosowanie.
— Charles Duffy

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

3
To nie jest sposób, aby to zrobić ... negujesz stdout psswd, a następnie przeprowadzasz na nim jednoznaczny test. @duckworthd jest dobry.
— Ray Foss

Co więcej, ponieważ nie ma cytowania, test będzie źle działał, gdy zostanie wydrukowany, ale zawiera więcej niż jedno słowo lub jest wyrażeniem globalnym pasującym do plików w bieżącym katalogu itp.
— Charles Duffy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.