Как вы можете запустить команду в 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 из этого.
ДонГар

Если вы думаете, что вам нужно отменить это, просто откройте новый экземпляр вашей оболочки (например, введите «bash») и, когда вы хотите отменить его, перейдите в другое окно терминала и убейте недавно порожденный bash обработать.
Этан

50
Это легко сделать из Ctr-C: until passwd; do echo "Try again"; sleep 2; done- все, что вам нужно сделать, это нажать Ctr-C сразу после (в течение двух секунд) выполнения echoсвоей работы.
Кристиан

9
@azmeuk: попробуйте что-то вроде until passwd || (( count++ >= 5 )); do echo "foo"; done(только bash, убедитесь, что для счетчика установлено значение 0, если эта переменная существует). Если вам нужно это для простого sh, увеличьте счетчик в теле и используйте []
Джастин Сейн,

2
После многократного обращения к этой странице я решил создать общую функцию bash для повтора команд, вот она: gist.github.com/felipou/6fbec22c4e04d3adfae5
felipou

94

$?Вместо этого вам нужно проверить , что является статусом выхода предыдущей команды. passwdвыходит с 0, если все работало нормально, и с ненулевым, если изменение пароля не удалось (неправильный пароль, несоответствие пароля и т. д.)

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

С вашей кавычкой версии, вы сравниваете вывод PASSWD, которая бы такие вещи , как Enter passwordи confirm passwordи тому подобное.


2
Не должно ли это быть $??
Шон Чин

Мне это нравится, потому что понятно, как адаптировать его для противоположной ситуации. например, запустить программу с недетерминированной ошибкой, пока она не даст сбой
Эрик

Когда успех обозначен ненулевым кодом выхода, это то, что вам нужно.
Гудлаугур Эгильссон

2
Я думаю, что это можно немного улучшить, изменив первый passwdна, /bin/falseесли у вас есть длинная и сложная команда, для которой вы не хотите сохранять две версии.
coladict

Должен быть принятый ответ imho. Это должно работать в большинстве оболочек (проверено в bash, mksh и ash) и легко адаптируется к ситуации.
linuxandria

73

Чтобы уточнить ответ @Marc B,

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

Это хороший способ сделать то же самое, что не зависит от конкретной команды.


11
К сожалению, у меня не работает (команда '!!' не найдена). Как это должно работать?
Йоханнес Рудольф

2
Это хитрость для запуска предыдущей команды. Например, если вы забыли написать sudoперед командой, вы можете просто sudo !!выполнить предыдущую команду с привилегиями root.
JohnEye

1
Могу
ли

2
Как спать между пробежками?
Камиль

6

Вы можете использовать бесконечный цикл для достижения этой цели:

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

2
Это единственный ответ, который не требует ввода моей многострочной команды в функцию. Я сделал && breakпосле моей команды проверки, хотя вместо выбора случая.
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быть сам по себе работать в качестве команды, а статус выхода этой вторичной команды , чтобы быть тем, что петля решает бежать или не дальше; это только если не будет не стандартный вывод о том , что статус выхода из самой команды считается , когда замена команды присутствует.
Чарльз Даффи

$commandтакже не является хорошим заполнителем - см. BashFAQ # 50 о том, почему использование строк для хранения команд изначально ненадежно. Тем не менее, это лучше, чем было; пониженный голос отозван.
Чарльз Даффи

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

3
Это не способ сделать это ... вы отрицаете стандартный вывод psswd, а затем делаете унарный тест на нем. @ Duckworthd это хорошо.
Рэй Фосс

Кроме того, потому что не цитирую, тест будет шалить , когда есть выход , но это больше , чем одно слово, или выражение Glob , что соответствует файлам в текущей директории, или так далее.
Чарльз Даффи
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.