Как запросить Да / Нет / Отменить ввод в сценарии оболочки Linux?
1445
Я хочу приостановить ввод в сценарии оболочки и предложить пользователю выбор.
Стандартный Yes, Noили Cancelтипа вопрос.
Как мне сделать это в типичной командной строке?
Так же, как примечание: соглашение для приглашений таково, что если вы представите [yn]опцию, то заглавная будет по умолчанию, то есть по [Yn]умолчанию «да», а по [yN]умолчанию «нет». См. Ux.stackexchange.com/a/40445/43532
Tyzoid
Любой, кто приходит сюда из ZSH, видит этот ответ, чтобы узнать, как использовать readкоманду для запроса
smac89
Ответы:
1620
Самым простым и наиболее доступным способом получения пользовательского ввода в командной строке является readкоманда. Лучший способ проиллюстрировать его использование - это простая демонстрация:
while true;do
read -p "Do you wish to install this program?" yn
case $yn in[Yy]*) make install;break;;[Nn]*) exit;;*) echo "Please answer yes or no.";;esacdone
Другой метод, указал на Стивене Huwig , является в Bash selectкоманды. Вот тот же пример с использованием select:
echo "Do you wish to install this program?"
select yn in"Yes""No";docase $yn inYes) make install;break;;No) exit;;esacdone
При этом selectвам не нужно очищать ввод - он отображает доступные варианты, и вы вводите число, соответствующее вашему выбору. Он также зацикливается автоматически, поэтому нет необходимости while trueповторять цикл, если они дают неверный ввод.
Кроме того, Леа Гри продемонстрировала способ сделать язык запроса независимым в своем ответе . Адаптация моего первого примера для лучшего обслуживания нескольких языков может выглядеть следующим образом:
set-- $(locale LC_MESSAGES)
yesptrn="$1"; noptrn="$2"; yesword="$3"; noword="$4"while true;do
read -p "Install (${yesword} / ${noword})? " yn
case $yn in
${yesptrn##^} ) make install; break;;
${noptrn##^} ) exit;;*) echo "Answer ${yesword} / ${noword}.";;esacdone
Очевидно, что другие коммуникационные строки здесь остаются непереведенными (Install, Answer), которые должны быть учтены в более законченном переводе, но даже частичный перевод был бы полезен во многих случаях.
Использование Bash в OS X Leopard, я изменил , exitчтобы breakсохранить от не закрывая вкладку , когда я выбрал «нет».
Трей Пипмайер
1
Как это работает с опциями дольше, чем Да или Нет? В случае case вы пишете что-то вроде: Установите программу и ничего не делайте потом) make install; перемена;
Шон
1
@Shawn Используя read, вы, конечно, можете использовать любой шаблон glob или regex, поддерживаемый оператором switch оболочки bash. Он просто сопоставляет текст, набранный с вашими шаблонами, пока не найдет совпадение. Используя select , команда получает список вариантов выбора и отображает их пользователю. Вы можете иметь элементы в списке так долго или так быстро, как вам нравится. Я рекомендую проверить их справочные страницы для всесторонней информации об использовании.
Мирддин Эмрис
3
почему breakв, selectесли нет петли?
Jayen
1
@akostadinov Я действительно должен больше читать историю редактирования. Вы правы, я не прав, и я внес ошибку, следуя совету Джаяна, ха. Ошибка была позже исправлена, но изменения были настолько далеки друг от друга, что я даже не вспомнил, что менял их.
Мирддин Эмрис
527
Как минимум пять ответов на один общий вопрос.
В зависимости от
POSIX совместимость: может работать на плохих системах с универсальным ракушка окружающая среда
ударспецифический: использование так называемых башмизмов
и если вы хотите
простой `` in line '' вопрос / ответ (общие решения)
довольно отформатированные интерфейсы, вроде Ncurses или более графический, используя libgtk или libqt ...
использовать мощные возможности истории чтения строки
1. Общие решения POSIX
Вы можете использовать readкоманду, а затем if ... then ... else:
echo -n "Is this a good question (y/n)? "
read answer
(Благодаря комментарию Адама Каца : заменил приведенный выше тест на более переносимый и исключающий одну развилку :)
POSIX, но особенность одного ключа
Но если вы не хотите, чтобы пользователь нажимал Return, вы можете написать:
( Отредактировано: как справедливо предположил @JonathanLeffler, сохранение конфигурации stty может быть лучше, чем просто принудительное их исправление .)
echo -n "Is this a good question (y/n)? "
old_stty_cfg=$(stty -g)
stty raw -echo ; answer=$(head -c 1); stty $old_stty_cfg # Careful playing with sttyif echo "$answer"| grep -iq "^y";then
echo Yeselse
echo Nofi
Примечание: это было проверено в соответствии сш, удар, КШ, тире а также BusyBox!
То же самое, но ожидая явно yили n:
#/bin/sh
echo -n "Is this a good question (y/n)? "
old_stty_cfg=$(stty -g)
stty raw -echo
answer=$(while! head -c 1| grep -i '[ny]';do true ;done)
stty $old_stty_cfg
if echo "$answer"| grep -iq "^y";then
echo Yeselse
echo Nofi
Использование специальных инструментов
Есть много инструментов , которые были построены с использованием libncurses, libgtk, libqtили другие графические библиотеки. Например, используя whiptail:
if whiptail --yesno "Is this a good question"2060;then
echo Yeselse
echo Nofi
В зависимости от вашей системы вам может потребоваться заменить whiptailдругой похожий инструмент:
dialog --yesno "Is this a good question"2060&& echo Yes
gdialog --yesno "Is this a good question"2060&& echo Yes
kdialog --yesno "Is this a good question"2060&& echo Yes
где 20высота диалогового окна в количестве строк и 60ширина диалогового окна. Эти инструменты имеют почти одинаковый синтаксис.
read -p "Is this a good question (y/n)? " answer
case ${answer:0:1}in
y|Y )
echo Yes;;*)
echo No;;esac
Я предпочитаю использовать, caseчтобы я мог даже проверить, yes | ja | si | ouiесли нужно ...
в соответствии с одной ключевой особенностью
В bash мы можем указать длину предполагаемого ввода для readкоманды:
read -n 1-p "Is this a good question (y/n)? " answer
В bash readкоманда принимает параметр времени ожидания , который может быть полезен.
read -t 3-n 1-p "Is this a good question (y/n)? " answer
[-z "$answer"]&& answer="Yes"# if 'yes' have to be default choice
3. Некоторые приемы для специальных инструментов
Более сложные диалоговые окна, помимо простых yes - noцелей:
dialog --menu "Is this a good question"206012 y Yes n No m Maybe
Индикатор:
dialog --gauge "Filling the tank"20600<<(for i in{1..100};do
printf "XXX\n%d\n%(%a %b %T)T progress: %d\nXXX\n" $i -1 $i
sleep .033done)
Маленькая демка:
#!/bin/shwhile true ;do[-x "$(which ${DIALOG%% *})"]|| DIALOG=dialog
DIALOG=$($DIALOG --menu "Which tool for next run?"2060122>&1 \
whiptail "dialog boxes from shell scripts">/dev/tty \
dialog "dialog boxes from shell with ncurses" \
gdialog "dialog boxes from shell with Gtk" \
kdialog "dialog boxes from shell with Kde")|| exit
clear;echo "Choosed: $DIALOG."for i in`seq 1 100`;do
date +"`printf "XXX\n%d\n%%a %%b %%T progress:%d\nXXX\n" $i $i`"
sleep .0125done| $DIALOG --gauge "Filling the tank"20600
$DIALOG --infobox "This is a simple info box\n\nNo action required"2060
sleep 3if $DIALOG --yesno "Do you like this demo?"2060;thenAnsYesNo=Yes;elseAnsYesNo=No;fiAnsInput=$($DIALOG --inputbox "A text:"2060"Text here..."2>&1>/dev/tty)AnsPass=$($DIALOG --passwordbox "A secret:"2060"First..."2>&1>/dev/tty)
$DIALOG --textbox /etc/motd 2060AnsCkLst=$($DIALOG --checklist "Check some..."206012 \
Correct"This demo is useful" off \
Fun"This demo is nice" off \
Strong"This demo is complex" on 2>&1>/dev/tty)AnsRadio=$($DIALOG --radiolist "I will:"206012 \
" -1""Downgrade this answer" off \
" 0""Not do anything" on \
" +1""Upgrade this anser" off 2>&1>/dev/tty)
out="Your answers:\nLike: $AnsYesNo\nInput: $AnsInput\nSecret: $AnsPass"
$DIALOG --msgbox "$out\nAttribs: $AnsCkLst\nNote: $AnsRadio"2060done
Обратите внимание , что sttyобеспечивает -gвозможность для использования: old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty". Это восстанавливает настройку в точности так, как они были найдены, которая может совпадать или не совпадать с stty -sane.
Джонатан Леффлер
3
read answerбудет интерпретировать обратную косую черту перед пробелами и переводами строки, и в противном случае удалит их, что редко требуется. Используйте read -r answerвместо этого согласно SC2162 .
vlfig
1
Метод «Использование истории readline» так ужасно не подходит для вопроса ОП. Я рад, что ты все равно включил это. У меня есть десятки гораздо более сложных сценариев, которые я собираюсь обновить с помощью этого шаблона!
Бруно Броноски
5
Вы можете использовать как caseдля POSIX, так и для bash (используйте подстановочный знак вместо подстроки bash:) case $answer in; [Yy]* ) echo Yes ;;, но я предпочитаю вместо этого использовать условный оператор, отдавая предпочтение [ "$answer" != "${answer#[Yy]}" ]вашему echo "$answer" | grep -iq ^y. Он более переносим (некоторые не-GNU greps не реализуются -qправильно) и не имеет системного вызова. ${answer#[Yy]}использует расширение параметра, чтобы удалить Yили yиз начала $answer, вызывая неравенство, когда либо присутствует. Это работает в любой оболочке POSIX (dash, ksh, bash, zsh, busybox и т. Д.).
Адам Кац
1
@CarterPape Да, это была шутка! Но в этом подробном ответе вы можете найти много советов (во втором пункте представлены как минимум 3 различных метода)! И ... примерно через 5 лет вы первыми расскажете о моем методе подсчета! ;-))
Ф. Хаури
349
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
Я не согласен, потому что он реализует только часть функциональности диалога «Да, Нет, Отмена» в DOS. Часть, которую он не может реализовать, это проверка ввода ... зацикливание, пока не будет получен правильный ответ.
Мирддин Эмрис
1
(Первоначальный заголовок вопроса был «Как мне
запросить
8
Но исходное описание вопроса остается неизменным и всегда запрашивается ответ на запрос «Да / Нет / Отмена». Название было обновлено, чтобы быть более понятным, чем мой оригинальный, но описание вопроса было всегда ясно (по моему мнению).
Мирддин Эмрис,
165
Вы можете использовать встроенную команду чтения ; Используйте -pопцию, чтобы ответить пользователю с вопросом.
Начиная с BASH4, теперь вы можете использовать, -iчтобы предложить ответ:
read -e -p "Enter the path to the file: "-i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(Но не забудьте использовать опцию «readline», -eчтобы разрешить редактирование строки с помощью клавиш со стрелками)
Если вам нужна логика «да / нет», вы можете сделать что-то вроде этого:
read -e -p "
List the content of your home dir ? [Y/n] " YN
[[ $YN =="y"|| $YN =="Y"|| $YN ==""]]&& ls -la ~/
Следует отметить, что FILEPATHэто имя переменной, которое вы выбрали, и задается в ответе на командную строку. Так что если бы вы запустили vlc "$FILEPATH", например, vlcоткрыли бы этот файл.
Кен Шарп
В чем выгода -eво втором примере (просто да / нет)?
JBallin
Любая причина использовать -e -pвместо -ep?
JBallin
1
Без -eфлажка / опции вы можете (в зависимости от реализации) не иметь возможности набрать «y», а затем передумать и заменить его на «n» (или что-нибудь еще в этом отношении); При документировании команды перечисление параметров по отдельности лучше для удобства чтения / ясности, среди прочих причин.
Поставьте четыре пробела в начале каждой строки, чтобы сохранить форматирование кода.
Джуни К. Сеппанен
10
Почему мы предоставляем 'y' и 'n' в качестве параметров для запроса (), если переключатели регистра жестко закодированы? Это просто просит злоупотребления. Это фиксированные параметры, которые нельзя изменить, поэтому эхо в строке 2 должно выглядеть следующим образом: echo -n "$ 1 [Y / N]?" Они не могут быть изменены, поэтому их не следует указывать.
Мирддин Эмрис
1
@ MyrddinEmrys Не могли бы вы разработать свой комментарий? Или разместите ссылку на статью или пару ключевых слов, чтобы я мог провести исследование самостоятельно.
Матеуш Пиотровски
4
@MateuszPiotrowski Ответ был отредактирован и улучшен, так как я сделал свой комментарий. Вы можете нажать ссылку «Отредактировано 23 декабря» выше, чтобы просмотреть все предыдущие версии этого ответа. Еще в 2008 году код был совсем другим.
Мирддин Эмрис
27
Ты хочешь:
Встроенные команды Bash (т.е. переносимые)
Проверьте TTY
Ответ по умолчанию
Тайм-аут
Цветной вопрос
отрывок
do_xxxx=y # In batch mode => Default is Yes[[-t 0]]&&# If TTY => Prompt the question
read -n 1-p $'\e[1;32m
Do xxxx? (Y/n)\e[0m ' do_xxxx # Store the answer in $do_xxxxif[[ $do_xxxx =~^(y|Y|)$ ]]# Do if 'y' or 'Y' or emptythen
xxxx
fi
Пояснения
[[ -t 0 ]] && read ... => Команда вызова read если TTY
read -n 1 => Ждать одного символа
$'\e[1;32m ... \e[0m ' => Печать зеленым цветом
(зеленый хорошо, потому что читается на белом / черном фоне)
[[ $do_xxxx =~ ^(y|Y|)$ ]] => Bash регулярное выражение
@Jav эхо печатает новую строку после вашего ответа. Без него следующая вещь, которая будет напечатана, появится сразу после вашего ответа в той же строке. Попробуйте удалить, echoчтобы убедиться в этом.
Деннис
13
Чтобы получить красивое поле ввода, похожее на ncurses, используйте командный диалог :
#!/bin/bashif(dialog --title "Message"--yesno "Want to do something risky?"625)# message box will have the size 25x6 charactersthen
echo "Let's do something risky"# do something riskyelse
echo "Let's stay boring"fi
Диалоговый пакет устанавливается по умолчанию как минимум с SUSE Linux. Похоже:
да, -e-iне работай в sh (оболочка Bourne), но вопрос специально помечен как bash ..
Джахид
12
Вы можете использовать значение REPLYпо умолчанию для a read, преобразовать в нижний регистр и сравнить с набором переменных с выражением.
Сценарий также поддерживает ja/ si/oui
read -rp "Do you want a demo? [y/n/c] "[[ ${REPLY,,}=~^(c|cancel)$ ]]&&{ echo "Selected Cancel"; exit 1;}if[[ ${REPLY,,}=~^(y|yes|j|ja|s|si|o|oui)$ ]];then
echo "Positive"fi
Можно обрабатывать с учетом локали «выбор да / нет» в оболочке POSIX; используя записи LC_MESSAGESкатегории локали, witch предоставляет готовые шаблоны RegEx для соответствия входным данным и строки для локализованного Да Нет.
#!/usr/bin/env sh# Getting LC_MESSAGES values into variables# shellcheck disable=SC2046 # Intended IFS splitting
IFS='
'set-- $(locale LC_MESSAGES)
yesexpr="$1"
noexpr="$2"
yesstr="$3"
nostr="$4"
messages_codeset="$5"# unused here, but kept as documentation# Display Yes / No ? prompt into locale
echo "$yesstr / $nostr ?"# Read answer
read -r yn
# Test answercase"$yn"in# match only work with the character class from the expression
${yesexpr##^}) echo "answer $yesstr" ;;
${noexpr##^}) echo "answer $nostr" ;;esac
yesstrИ nostrлокал ключевые слова и YESSTRи NOSTRlanginfo элементов ранее были использованы для пользовательского матча позитивных и негативных ответов. В POSIX.1-2008, тем yesexpr, noexpr, YESEXPR, и NOEXPRрасширенные регулярные выражения заменили их. Приложения должны использовать общие средства обмена сообщениями на основе локали для выдачи сообщений с подсказками, которые содержат примеры желаемых ответов.
В качестве альтернативы, используя локализацию Bash:
Мне нравится добавление опций, не зависящих от языка. Отлично сработано.
Мирддин Эмрис
1
К сожалению, POSIX указывает только первые два (yesexpr и noexpr). В Ubuntu 16 yesstr и nostr пусты.
Урхиксидур
1
Но ждать! Есть плохие новости! Выражения оператора случая bash не являются регулярными, они являются выражениями имени файла. Таким образом, yesexpr и noexpr в Ubuntu 16 («^ [yY]. *» И «^ [nN]. *» Соответственно) завершатся неудачно из-за встроенного периода. В регулярном выражении «. *» Означает «любой не символ новой строки, ноль или более раз». Но в случае с кейсом это буквальное "." с последующим любым количеством символов.
Урхиксидур
1
Наконец самое лучшее , что можно сделать с помощью yesexprи noexprв среде оболочки, является использование его в согласовании конкретных RegEx Bashif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
Леа Gris
10
Только одно нажатие
Вот более длинный, но многократно используемый и модульный подход:
Возвращает 0= да и 1= нет
Не нужно нажимать ввод - только один символ
Нажмите, enterчтобы принять выбор по умолчанию
Можно отключить выбор по умолчанию для принудительного выбора
Работает для обоих zshи bash.
По умолчанию «нет» при нажатии Enter
Обратите внимание, что Nзаглавная. Здесь нажимается ввод, принимая значение по умолчанию:
Выше я просто нажал клавишу ввода, поэтому команда запустилась.
Нет по умолчанию enter- требуется yилиn
$ get_yes_keypress "Here you cannot press enter. Do you like this [y/n]? "
Here you cannot press enter. Do you like this [y/n]? k
Here you cannot press enter. Do you like this [y/n]?
Here you cannot press enter. Do you like this [y/n]? n
$ echo $?
1
Здесь 1или ложь была возвращена. Обратите внимание, что с помощью этой функции более низкого уровня вам нужно будет предоставить собственное [y/n]?приглашение.
Код
# Read a single char from /dev/tty, prompting with "$*"# Note: pressing enter will return a null string. Perhaps a version terminated with X and then remove it in caller?# See https://unix.stackexchange.com/a/367880/143394 for dealing with multi-byte, etc.function get_keypress {local REPLY IFS=>/dev/tty printf '%s'"$*"[[ $ZSH_VERSION ]]&& read -rk1 # Use -u0 to read from STDIN# See https://unix.stackexchange.com/q/383197/143394 regarding '\n' -> ''[[ $BASH_VERSION ]]&&</dev/tty read -rn1
printf '%s'"$REPLY"}# Get a y/n from the user, return yes=0, no=1 enter=$2# Prompt using $1.# If set, return $2 on pressing enter, useful for cancel or defualtingfunction get_yes_keypress {local prompt="${1:-Are you sure [y/n]? }"local enter_return=$2
local REPLY
# [[ ! $prompt ]] && prompt="[y/n]? "while REPLY=$(get_keypress "$prompt");do[[ $REPLY ]]&& printf '\n'# $REPLY blank if user presses entercase"$REPLY"in
Y|y)return0;;
N|n)return1;;'')[[ $enter_return ]]&&return"$enter_return"esacdone}# Credit: http://unix.stackexchange.com/a/14444/143394# Prompt to confirm, defaulting to NO on <enter># Usage: confirm "Dangerous. Are you sure?" && rm *function confirm {local prompt="${*:-Are you sure} [y/N]? "
get_yes_keypress "$prompt"1}# Prompt to confirm, defaulting to YES on <enter>function confirm_yes {local prompt="${*:-Are you sure} [Y/n]? "
get_yes_keypress "$prompt"0}
Когда я тестировал этот сценарий, вместо вышеприведенного результата я получил, Show dangerous command [y/N]? [y/n]?иShow dangerous command [Y/n]? [y/n]?
Илиас Карим
Спасибо @IliasKarim, я исправил это только сейчас.
Том Хейл,
9
Извините за публикацию на такой старый пост. Несколько недель назад я столкнулся с подобной проблемой, в моем случае мне нужно было решение, которое также работало в онлайн-установочном скрипте, например:curl -Ss https://raw.github.com/_____/installer.sh | bash
Использование read yesno < /dev/ttyотлично работает для меня:
echo -n "These files will be uploaded. Is this ok? (y/n) "
read yesno </dev/tty
if["x$yesno"="xy"];then# Yeselse# Nofi
Важной частью этого является проверка входных данных. Я думаю, что адаптация моего первого примера так, чтобы он принимал ttyввод, как вы это сделали, также сработала бы для вас, а также получила бы цикл при неправильном вводе (представьте несколько символов в буфере; ваш метод заставит пользователя всегда выбирать нет).
Мирддин Эмрис
7
Я заметил, что никто не опубликовал ответ, показывающий многострочное эхо-меню для такого простого пользовательского ввода, так что вот мое мнение:
Один простой способ сделать это с помощью xargs -pили GNU parallel --interactive.
Мне нравится поведение xargs немного лучше, потому что оно выполняет каждую команду сразу после приглашения, как и другие интерактивные команды unix, вместо того, чтобы собирать дачи для выполнения в конце. (Вы можете Ctrl-C после того, как вы пройдете через те, которые вы хотели.)
Неплохо, но xargs --interactiveограничено да или нет. Пока это все, что вам нужно, этого может быть достаточно, но мой оригинальный вопрос привел пример с тремя возможными результатами. Мне действительно нравится, что это поток, хотя; многие распространенные сценарии извлекут выгоду из его способности быть переданным по трубопроводу.
Мирддин Эмрис
Понимаю. Я думал, что «отмена» означает просто остановить все дальнейшее выполнение, которое поддерживается с помощью Ctrl-C, но если вам нужно сделать что-то более сложное при отмене (или нет), этого будет недостаточно.
Джошуа Гольдберг
3
В качестве друга однострочной команды я использовал следующее:
Можете ли вы уточнить использование переменной подсказки? Похоже, он вытерся после того, как один лайнер, так как вы используете линию, чтобы сделать что-нибудь?
Мирддин Эмрис
приглашение стирается после цикла while. Потому что я хочу, чтобы переменная подсказки была инициализирована впоследствии (поскольку я чаще использую оператор). Наличие этой строки в shell-скрипте будет продолжаться только в том случае, если набрано y | Y, и завершится, если набрано n | N, или повторите запрос ввода для всего остального.
ccDict
3
Я использовал это caseутверждение пару раз в таком сценарии, и использование статистики случая - хороший способ сделать это. whileПетля, что ecapsulates в caseблоке, который использует логическое условие может быть реализована для того , чтобы провести еще больший контроль над программой, и выполнить множество других требований. После того, как все условия будут выполнены, breakможно будет использовать элемент управления, который вернет управление в основную часть программы. Кроме того, для удовлетворения других условий, конечно, могут быть добавлены условные операторы, сопровождающие управляющие структуры: caseоператор и возможный whileцикл.
Пример использования caseвыписки для выполнения вашего запроса
#! /bin/sh # For potential users of BSD, or other systems who do not# have a bash binary located in /bin the script will be directed to# a bourne-shell, e.g. /bin/sh# NOTE: It would seem best for handling user entry errors or# exceptions, to put the decision required by the input # of the prompt in a case statement (case control structure),
echo Would you like us to perform the option:"(Y|N)"
read inPut
case $inPut in# echoing a command encapsulated by # backticks (``) executes the command"Y") echo `Do something crazy`;;# depending on the scenario, execute the other option# or leave as default"N") echo `execute another option`;;esac
exit
Это кажется сложным и хрупким. Как насчет только чтоyn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure
tripleee
2
В ответ на других:
Вам не нужно указывать регистр в BASH4, просто используйте «,,», чтобы сделать переменную в нижнем регистре. Также мне очень не нравится помещать код внутри блока чтения, получать результат и иметь дело с ним вне IMO блока чтения. Также добавьте «q» для выхода из IMO. И наконец, почему введите «да», просто используйте -n1 и нажмите клавишу y.
Пример: пользователь может нажать y / n, а также q, чтобы просто выйти.
ans=''while true;do
read -p "So is MikeQ the greatest or what (y/n/q) ?"-n1 ans
case ${ans,,}in
y|n|q)break;;*) echo "Answer y for yes / n for no or q for quit.";;esacdone
echo -e "\nAnswer = $ans"if[["${ans,,}"=="q"]];then
echo "OK Quitting, we will assume that he is"
exit 0fiif[["${ans,,}"=="y"]];then
echo "MikeQ is the greatest!!"else
echo "No? MikeQ is not the greatest?"fi
В большинстве случаев в таких сценариях необходимо продолжать выполнение сценария до тех пор, пока пользователь не продолжит вводить «да», и останавливать его нужно только тогда, когда пользователь вводит «нет». Приведенный ниже фрагмент поможет вам достичь этого!
#!/bin/bash
input="yes"while["$input"=="yes"]do
echo "execute script functionality here..!!"
echo "Do you want to continue (yes/no)?"
read input
done
[yn]
опцию, то заглавная будет по умолчанию, то есть по[Yn]
умолчанию «да», а по[yN]
умолчанию «нет». См. Ux.stackexchange.com/a/40445/43532read
команду для запросаОтветы:
Самым простым и наиболее доступным способом получения пользовательского ввода в командной строке является
read
команда. Лучший способ проиллюстрировать его использование - это простая демонстрация:Другой метод, указал на Стивене Huwig , является в Bash
select
команды. Вот тот же пример с использованиемselect
:При этом
select
вам не нужно очищать ввод - он отображает доступные варианты, и вы вводите число, соответствующее вашему выбору. Он также зацикливается автоматически, поэтому нет необходимостиwhile true
повторять цикл, если они дают неверный ввод.Кроме того, Леа Гри продемонстрировала способ сделать язык запроса независимым в своем ответе . Адаптация моего первого примера для лучшего обслуживания нескольких языков может выглядеть следующим образом:
Очевидно, что другие коммуникационные строки здесь остаются непереведенными (Install, Answer), которые должны быть учтены в более законченном переводе, но даже частичный перевод был бы полезен во многих случаях.
Наконец, пожалуйста , проверьте отличный ответ на Ф. Хаури .
источник
exit
чтобыbreak
сохранить от не закрывая вкладку , когда я выбрал «нет».break
в,select
если нет петли?Как минимум пять ответов на один общий вопрос.
В зависимости от
и если вы хотите
1. Общие решения POSIX
Вы можете использовать
read
команду, а затемif ... then ... else
:(Благодаря комментарию Адама Каца : заменил приведенный выше тест на более переносимый и исключающий одну развилку :)
POSIX, но особенность одного ключа
Но если вы не хотите, чтобы пользователь нажимал Return, вы можете написать:
( Отредактировано: как справедливо предположил @JonathanLeffler, сохранение конфигурации stty может быть лучше, чем просто принудительное их исправление .)
Примечание: это было проверено в соответствии сш, удар, КШ, тире а также BusyBox!
То же самое, но ожидая явно yили n:
Использование специальных инструментов
Есть много инструментов , которые были построены с использованием
libncurses
,libgtk
,libqt
или другие графические библиотеки. Например, используяwhiptail
:В зависимости от вашей системы вам может потребоваться заменить
whiptail
другой похожий инструмент:где
20
высота диалогового окна в количестве строк и60
ширина диалогового окна. Эти инструменты имеют почти одинаковый синтаксис.2. Bash конкретные решения
Основной в линии метод
Я предпочитаю использовать,
case
чтобы я мог даже проверить,yes | ja | si | oui
если нужно ...в соответствии с одной ключевой особенностью
В bash мы можем указать длину предполагаемого ввода для
read
команды:В bash
read
команда принимает параметр времени ожидания , который может быть полезен.3. Некоторые приемы для специальных инструментов
Более сложные диалоговые окна, помимо простых
yes - no
целей:Индикатор:
Маленькая демка:
Больше образца? Посмотрите Использование Whiptail для выбора USB-устройства и USB-накопителя: USBKeyChooser
5. Использование истории readline
Пример:
Это создаст файл
.myscript.history
в вашем$HOME
каталоге, чем вы могли бы использовать команды истории Readline, как и Up, Down, Ctrl+ rи другие.источник
stty
обеспечивает-g
возможность для использования:old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty"
. Это восстанавливает настройку в точности так, как они были найдены, которая может совпадать или не совпадать сstty -sane
.read answer
будет интерпретировать обратную косую черту перед пробелами и переводами строки, и в противном случае удалит их, что редко требуется. Используйтеread -r answer
вместо этого согласно SC2162 .case
для POSIX, так и для bash (используйте подстановочный знак вместо подстроки bash:)case $answer in; [Yy]* ) echo Yes ;;
, но я предпочитаю вместо этого использовать условный оператор, отдавая предпочтение[ "$answer" != "${answer#[Yy]}" ]
вашемуecho "$answer" | grep -iq ^y
. Он более переносим (некоторые не-GNU greps не реализуются-q
правильно) и не имеет системного вызова.${answer#[Yy]}
использует расширение параметра, чтобы удалитьY
илиy
из начала$answer
, вызывая неравенство, когда либо присутствует. Это работает в любой оболочке POSIX (dash, ksh, bash, zsh, busybox и т. Д.).источник
Вы можете использовать встроенную команду чтения ; Используйте
-p
опцию, чтобы ответить пользователю с вопросом.Начиная с BASH4, теперь вы можете использовать,
-i
чтобы предложить ответ:(Но не забудьте использовать опцию «readline»,
-e
чтобы разрешить редактирование строки с помощью клавиш со стрелками)Если вам нужна логика «да / нет», вы можете сделать что-то вроде этого:
источник
FILEPATH
это имя переменной, которое вы выбрали, и задается в ответе на командную строку. Так что если бы вы запустилиvlc "$FILEPATH"
, например,vlc
открыли бы этот файл.-e
во втором примере (просто да / нет)?-e -p
вместо-ep
?-e
флажка / опции вы можете (в зависимости от реализации) не иметь возможности набрать «y», а затем передумать и заменить его на «n» (или что-нибудь еще в этом отношении); При документировании команды перечисление параметров по отдельности лучше для удобства чтения / ясности, среди прочих причин.Bash выбрал для этой цели.
источник
exit
внутренность :)Ctrl-D
Но, конечно, для реального кода, использующего его, потребуется разрыв или выход в теле.)exit
выйдет из сценария все вместе,break
выйдет только из цикла, в котором вы находитесь (если вы находитесь в циклеwhile
илиcase
)источник
Вот что я собрал:
Я новичок, поэтому возьмите это с крошкой соли, но, похоже, это сработает.
источник
case $yn in
на,case ${yn:-$2} in
то вы можете использовать второй аргумент в качестве значения по умолчанию, Y или N.case $yn
чтобыcase "${yn:-Y}"
иметь да по умолчаниюисточник
Ты хочешь:
отрывок
Пояснения
[[ -t 0 ]] && read ...
=> Команда вызоваread
если TTYread -n 1
=> Ждать одного символа$'\e[1;32m ... \e[0m '
=> Печать зеленым цветом(зеленый хорошо, потому что читается на белом / черном фоне)
[[ $do_xxxx =~ ^(y|Y|)$ ]]
=> Bash регулярное выражениеТайм-аут => Ответ по умолчанию - Нет
источник
Самый простой способ добиться этого с наименьшим количеством строк заключается в следующем:
Это
if
просто пример: вам решать, как обращаться с этой переменной.источник
Используйте
read
команду:а затем все остальные вещи, которые вам нужны
источник
Это решение читает один символ и вызывает функцию с ответом «да».
источник
echo
чтобы убедиться в этом.Чтобы получить красивое поле ввода, похожее на ncurses, используйте командный диалог :
Диалоговый пакет устанавливается по умолчанию как минимум с SUSE Linux. Похоже:
источник
-e
Опция позволяет пользователю редактировать ввод с помощью клавиш со стрелками.Если вы хотите использовать предложение в качестве входных данных:
-i
опция печатает суггестивный вводисточник
-e
-i
не работай в sh (оболочка Bourne), но вопрос специально помечен как bash ..Вы можете использовать значение
REPLY
по умолчанию для aread
, преобразовать в нижний регистр и сравнить с набором переменных с выражением.Сценарий также поддерживает
ja
/si
/oui
источник
Можно обрабатывать с учетом локали «выбор да / нет» в оболочке POSIX; используя записи
LC_MESSAGES
категории локали, witch предоставляет готовые шаблоны RegEx для соответствия входным данным и строки для локализованного Да Нет.РЕДАКТИРОВАТЬ: Как @Urhixidur отметил в своем комментарии :
См .: https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06.
В качестве альтернативы, используя локализацию Bash:
Ответ сопоставляется с использованием регулярных выражений, предусмотренных в локали.
Чтобы перевести остальные сообщения, используйте
bash --dump-po-strings scriptname
для вывода строки po для локализации:источник
yesexpr
иnoexpr
в среде оболочки, является использование его в согласовании конкретных RegEx Bashif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
Только одно нажатие
Вот более длинный, но многократно используемый и модульный подход:
0
= да и1
= нетzsh
иbash
.По умолчанию «нет» при нажатии Enter
Обратите внимание, что
N
заглавная. Здесь нажимается ввод, принимая значение по умолчанию:Также обратите внимание, что это
[y/N]?
было автоматически добавлено. По умолчанию «нет» принимается, поэтому ничего не отображается.Повторяйте запрос, пока не получите правильный ответ:
По умолчанию «да» при нажатии Enter
Обратите внимание, что
Y
заглавная:Выше я просто нажал клавишу ввода, поэтому команда запустилась.
Нет по умолчанию enter- требуется
y
илиn
Здесь
1
или ложь была возвращена. Обратите внимание, что с помощью этой функции более низкого уровня вам нужно будет предоставить собственное[y/n]?
приглашение.Код
источник
Show dangerous command [y/N]? [y/n]?
иShow dangerous command [Y/n]? [y/n]?
Извините за публикацию на такой старый пост. Несколько недель назад я столкнулся с подобной проблемой, в моем случае мне нужно было решение, которое также работало в онлайн-установочном скрипте, например:
curl -Ss https://raw.github.com/_____/installer.sh | bash
Использование
read yesno < /dev/tty
отлично работает для меня:Надеюсь, это кому-нибудь поможет.
источник
tty
ввод, как вы это сделали, также сработала бы для вас, а также получила бы цикл при неправильном вводе (представьте несколько символов в буфере; ваш метод заставит пользователя всегда выбирать нет).Я заметил, что никто не опубликовал ответ, показывающий многострочное эхо-меню для такого простого пользовательского ввода, так что вот мое мнение:
Этот метод был опубликован в надежде, что кто-то найдет его полезным и экономящим время.
источник
Вариант с множественным выбором:
Пример:
Он будет установлен
REPLY
наy
(внутри скрипта).источник
Я предлагаю вам использовать диалог ...
он прост и удобен в использовании, также есть версия gnome под названием gdialog, которая принимает те же параметры, но показывает стиль GUI на X.
источник
Вдохновленный ответами @Mark и @Myrddin, я создал эту функцию для универсального приглашения
используйте это так:
источник
более общим будет:
источник
Один простой способ сделать это с помощью
xargs -p
или GNUparallel --interactive
.Мне нравится поведение xargs немного лучше, потому что оно выполняет каждую команду сразу после приглашения, как и другие интерактивные команды unix, вместо того, чтобы собирать дачи для выполнения в конце. (Вы можете Ctrl-C после того, как вы пройдете через те, которые вы хотели.)
например,
источник
xargs --interactive
ограничено да или нет. Пока это все, что вам нужно, этого может быть достаточно, но мой оригинальный вопрос привел пример с тремя возможными результатами. Мне действительно нравится, что это поток, хотя; многие распространенные сценарии извлекут выгоду из его способности быть переданным по трубопроводу.В качестве друга однострочной команды я использовал следующее:
Написано longform, оно работает так:
источник
Я использовал это
case
утверждение пару раз в таком сценарии, и использование статистики случая - хороший способ сделать это.while
Петля, что ecapsulates вcase
блоке, который использует логическое условие может быть реализована для того , чтобы провести еще больший контроль над программой, и выполнить множество других требований. После того, как все условия будут выполнены,break
можно будет использовать элемент управления, который вернет управление в основную часть программы. Кроме того, для удовлетворения других условий, конечно, могут быть добавлены условные операторы, сопровождающие управляющие структуры:case
оператор и возможныйwhile
цикл.Пример использования
case
выписки для выполнения вашего запросаисточник
Да / Нет / Отмена
функция
Применение
Подтвердите с помощью чистого ввода пользователя
функция
Применение
источник
источник
yn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure
В ответ на других:
Вам не нужно указывать регистр в BASH4, просто используйте «,,», чтобы сделать переменную в нижнем регистре. Также мне очень не нравится помещать код внутри блока чтения, получать результат и иметь дело с ним вне IMO блока чтения. Также добавьте «q» для выхода из IMO. И наконец, почему введите «да», просто используйте -n1 и нажмите клавишу y.
Пример: пользователь может нажать y / n, а также q, чтобы просто выйти.
источник
В большинстве случаев в таких сценариях необходимо продолжать выполнение сценария до тех пор, пока пользователь не продолжит вводить «да», и останавливать его нужно только тогда, когда пользователь вводит «нет». Приведенный ниже фрагмент поможет вам достичь этого!
источник