В Bash, как добавить "Вы уверены [Y/n]" в любую команду или псевдоним?
В данном конкретном случае я хотел бы добавить подтверждение в Bash для
Уверены ли вы? [Y/ N]
для Mercurial hg push ssh://username@www.example.com//somepath/morepath
, который на самом деле является псевдонимом. Есть ли стандартная команда, которая может быть добавлена к псевдониму для достижения этого?
Причина в том, что hg push
а также hg out
может звучать похоже и иногда, когда я хочу hgoutrepo
Могу случайно набрать hgpushrepo
(оба псевдонимы).
Обновление: если это может быть что-то вроде встроенной команды с другой командой, такой как: confirm && hg push ssh://...
это было бы здорово... просто команда, которая может попросить yes
или же no
и продолжить с остальными, если yes
,
21 ответ
Это более компактные и универсальные формы ответаХэмиша. Они обрабатывают любую смесь прописных и строчных букв:
read -r -p "Are you sure? [y/N] " response
case "$response" in
[yY][eE][sS]|[yY])
do_something
;;
*)
do_something_else
;;
esac
Или для Bash >= версия 3.2:
read -r -p "Are you sure? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]
then
do_something
else
do_something_else
fi
Примечание: если $response
пустая строка, она выдаст ошибку. Чтобы исправить, просто добавьте кавычки: "$response"
, - Всегда используйте двойные кавычки в переменных, содержащих строки (например: предпочитайте использовать "$@"
вместо $@
).
Или Bash 4.x:
read -r -p "Are you sure? [y/N] " response
response=${response,,} # tolower
if [[ "$response" =~ ^(yes|y)$ ]]
...
Редактировать:
В ответ на ваши изменения вы можете создать и использовать confirm
Команда, основанная на первой версии в моем ответе (она будет работать аналогично двум другим):
confirm() {
# call with a prompt string or use a default
read -r -p "${1:-Are you sure? [y/N]} " response
case "$response" in
[yY][eE][sS]|[yY])
true
;;
*)
false
;;
esac
}
Чтобы использовать эту функцию:
confirm && hg push ssh://..
или же
confirm "Would you really like to do a push?" && hg push ssh://..
Вот примерно фрагмент, который вы хотите. Позвольте мне узнать, как направить аргументы.
read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt == "y" || $prompt == "Y" || $prompt == "yes" || $prompt == "Yes" ]]
then
# http://stackru.com/questions/1537673/how-do-i-forward-parameters-to-other-command-in-bash-script
else
exit 0
fi
Берегись yes | command name here
:)
Подтверждения легко обойти с помощью возврата каретки, и я считаю полезным постоянно запрашивать действительные данные.
Вот функция, чтобы сделать это легко. "неверный ввод" отображается красным, если Y|N не получено, и пользователю снова предлагается запрос.
prompt_confirm() {
while true; do
read -r -n 1 -p "${1:-Continue?} [y/n]: " REPLY
case $REPLY in
[yY]) echo ; return 0 ;;
[nN]) echo ; return 1 ;;
*) printf " \033[31m %s \n\033[0m" "invalid input"
esac
done
}
# example usage
prompt_confirm "Overwrite File?" || exit 0
Вы можете изменить приглашение по умолчанию, передав аргумент
Чтобы избежать явной проверки этих вариантов 'yes', вы можете использовать оператор регулярного выражения bash '=~' с регулярным выражением:
read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt =~ [yY](es)* ]]
then
(etc...)
Это проверяет, начинается ли пользовательский ввод с 'y' или 'Y' и сопровождается нулем или более 'es'.
Это может быть взломать
как в вопросе В Unix / Bash, является ли "xargs -p" хорошим способом запросить подтверждение перед выполнением какой-либо команды?
мы можем использовать xargs
сделать работу:
echo ssh://username@www.example.com//somepath/morepath | xargs -p hg push
конечно, это будет установлено как псевдоним, как hgpushrepo
Пример:
$ echo foo | xargs -p ls -l
ls -l foo?...y
-rw-r--r-- 1 mikelee staff 0 Nov 23 10:38 foo
$ echo foo | xargs -p ls -l
ls -l foo?...n
$
Это может быть слишком коротким, но для моего личного использования, это прекрасно работает
read -n 1 -p "Push master upstream? [Y/n] " reply;
if [ "$reply" != "" ]; then echo; fi
if [ "$reply" != "n" ]; then
git push upstream master
fi
read -n 1
просто читает один символ. Если это не строчная буква "n", то предполагается, что это буква "Y".
(что касается настоящего вопроса: создайте сценарий bash и измените псевдоним так, чтобы он указывал на этот сценарий, а не на то, на что он указывал ранее)
read -r -p "Are you sure? [Y/n]" response
response=${response,,} # tolower
if [[ $response =~ ^(yes|y| ) ]] || [[ -z $response ]]; then
your-action-here
fi
Добавьте следующее в ваш файл /etc/bashrc. Этот сценарий добавляет резидентную "функцию" вместо псевдонима "подтверждение".
function confirm( )
{
#alert the user what they are about to do.
echo "About to $@....";
#confirm with the user
read -r -p "Are you sure? [Y/n]" response
case "$response" in
[yY][eE][sS]|[yY])
#if yes, then execute the passed parameters
"$@"
;;
*)
#Otherwise exit...
echo "ciao..."
exit
;;
esac
}
Не нужно нажимать ввод
Вот более длинный, но многократно используемый и модульный подход:
- Возвращает
0
= да и1
= нет - Не нужно нажимать ввод - только один символ
- Нажмите Enter, чтобы принять выбор по умолчанию.
- Можно отключить выбор по умолчанию для принудительного выбора
- Работает для обоих
zsh
а такжеbash
,
По умолчанию "нет" при нажатии Enter
Обратите внимание, что N
с большой буквы Здесь нажимается ввод, принимая значение по умолчанию:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?
Также обратите внимание, что [y/N]?
был автоматически добавлен. По умолчанию "нет" принимается, поэтому ничего не отображается.
Повторяйте запрос, пока не получите правильный ответ:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *
По умолчанию "да" при нажатии Enter
Обратите внимание, что Y
с большой буквы:
$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *
Выше я просто нажал клавишу ввода, поэтому команда запустилась.
Нет по умолчанию при вводе - требуется y
или же n
$ get_yes_keypress "Here you cannot press enter. Do you like this"
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 defualting
function 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 enter
case "$REPLY" in
Y|y) return 0;;
N|n) return 1;;
'') [[ $enter_return ]] && return "$enter_return"
esac
done
}
# 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
}
Ну вот моя версия confirm
, модифицированный от Джеймса:
function confirm() {
local response msg="${1:-Are you sure} (y/[n])? "; shift
read -r $* -p "$msg" response || echo
case "$response" in
[yY][eE][sS]|[yY]) return 0 ;;
*) return 1 ;;
esac
}
Эти изменения:
- использование
local
чтобы предотвратить совпадение имен переменных read
использование$2 $3 ...
контролировать его действие, так что вы можете использовать-n
а также-t
- если
read
завершается неудачно,echo
перевод строки для красоты - мой
Git on Windows
только имеетbash-3.1
и не имеетtrue
или жеfalse
так что пользуйтесьreturn
вместо. Конечно, это также совместимо с bash-4.4 (текущим в Git для Windows). - используйте IPython-стиль "(y/[n])", чтобы четко указать, что "n" является значением по умолчанию.
Мне нравится выходить как можно скорее, если пользователь не уверен, и мне нравится, чтобы код был читабельным и коротким. В зависимости от того, хотите ли вы, чтобы пользователь нажимал клавишу «Ввод» после ответа или нет,
Нажав «Возврат»,
read -p "Warning: something scary: Continue (Y/N)? " reply
[ $reply != 'Y' ] && [ $reply != 'y' ] && echo 'Aborting' && exit 1
echo 'Scary thing'
или если вы предпочитаете не ждать, пока пользователь нажмет «Ввод»,
read -n1 -p "Warning: something scary: Continue (Y/N)? " reply
echo ''
[ $reply != 'Y' ] && [ $reply != 'y' ] && echo 'Aborting' && exit 1
echo 'Scary thing'
Другие ответы имеют фон на этом-n1
флаг и другие вариантыread
. echo ''
во 2-м варианте заключается в том, чтобы последующий вывод отображался в новой строке, поскольку пользователю не нужно нажимать клавишу «Ввод», поэтому на терминале не было отражено новой строки.
Эта версия позволяет иметь более одного случая y
или Y
, n
или N
При желании: повторяйте вопрос, пока не появится вопрос для утверждения.
При желании: игнорировать любой другой ответ
При желании: выйдите из терминала, если хотите
confirm() { echo -n "Continue? y or n? " read REPLY case $REPLY in [Yy]) echo 'yup y' ;; # you can change what you do here for instance [Nn]) break ;; # exit case statement gracefully # Here are a few optional options to choose between # Any other answer: # 1. Repeat the question *) confirm ;; # 2. ignore # *) ;; # 3. Exit terminal # *) exit ;; esac # REPLY='' }
Также обратите внимание: в последней строке этой функции очистите переменную REPLY. В противном случае, если выecho $REPLY
вы увидите, что он все еще установлен, пока вы не откроете или не закроете терминал или не установите его снова.
Пытаться,
#!/bin/bash
pause ()
{
REPLY=Y
while [ "$REPLY" == "Y" ] || [ "$REPLY" != "y" ]
do
echo -e "\t\tPress 'y' to continue\t\t\tPress 'n' to quit"
read -n1 -s
case "$REPLY" in
"n") exit ;;
"N") echo "case sensitive!!" ;;
"y") clear ;;
"Y") echo "case sensitive!!" ;;
* ) echo "$REPLY is Invalid Option" ;;
esac
done
}
pause
echo "Hi"
Поздно к игре, но я создал еще один вариант confirm
функции предыдущих ответов:
confirm ()
{
read -r -p "$(echo $@) ? [y/N] " YESNO
if [ "$YESNO" != "y" ]; then
echo >&2 "Aborting"
exit 1
fi
CMD="$1"
shift
while [ -n "$1" ]; do
echo -en "$1\0"
shift
done | xargs -0 "$CMD" || exit $?
}
Чтобы использовать это:
confirm your_command
Особенности:
- печатает вашу команду как часть приглашения
- передает аргументы с помощью разделителя NULL
- сохраняет состояние выхода вашей команды
ошибки:
echo -en
работает сbash
но может потерпеть неудачу в вашей оболочке- может потерпеть неудачу, если аргументы мешают
echo
или жеxargs
- миллиард других ошибок, потому что сценарии оболочки трудны
Я пытался установить ant с помощью команды bash, но получал
Error: Process completed with exit code 1.
Ниже команда работала для меня
sudo yes | apt install ant
Ниже код сочетает в себе две вещи
shopt -s nocasematch, который позаботится о регистронезависимости
и если условие, которое будет принимать оба входа либо вы передаете да, да, да, у.
shopt -s nocasematch
if [[sed-4.2.2. $ LINE = ~ (yes | y) $]]
затем выйдите из 0
фи
Да, по умолчанию на основе ответа Денниса Уильямсона
#!/bin/bash
confirm() {
# call with a prompt string or use a default
read -r -p "${1:-Are you sure?} [Y/n] " response
case "$response" in
@([nN])*([oO]))
false
;;
*)
true
;;
esac
}
Не то же самое, но идея, которая работает в любом случае.
#!/bin/bash
i='y'
while [ ${i:0:1} != n ]
do
# Command(s)
read -p " Again? Y/n " i
[[ ${#i} -eq 0 ]] && i='y'
done
Выход:
Снова? Да нет
Снова? Да ничего
Снова? Да / нет 7
Снова? Да / нет
Снова? Да нет нсиф
$
Теперь проверяет только 1-й символ $ я прочитал.
Вот мое решение, которое использует локализованное регулярное выражение. Таким образом, на немецком языке "j" для "Ja" будет интерпретироваться как "да".
Первый аргумент - это вопрос, если вторым аргументом является "y", то да будет ответом по умолчанию, иначе нет будет ответом по умолчанию. Возвращаемое значение равно 0, если ответом было "да", и 1, если ответом было "нет".
function shure(){
if [ $# -gt 1 ] && [[ "$2" =~ ^[yY]*$ ]] ; then
arg="[Y/n]"
reg=$(locale noexpr)
default=(0 1)
else
arg="[y/N]"
reg=$(locale yesexpr)
default=(1 0)
fi
read -p "$1 ${arg}? : " answer
[[ "$answer" =~ $reg ]] && return ${default[1]} || return ${default[0]}
}
Вот основное использование
# basic example default is no
shure "question message" && echo "answer yes" || echo "answer no"
# print "question message [y/N]? : "
# basic example default set to yes
shure "question message" y && echo "answer yes" || echo "answer no"
# print "question message [Y/n]? : "
Я знаю, что это старый вопрос, но он может кому-то помочь, здесь он не рассматривался.
Меня спросили, как использовать rm -i в сценарии, который получает ввод из файла. Поскольку ввод файла в сценарий обычно поступает из STDIN, нам необходимо изменить его, чтобы из STDIN получался только ответ на команду rm. Вот решение:
#!/bin/bash
while read -u 3 line
do
echo -n "Remove file $line?"
read -u 1 -n 1 key
[[ $key = "y" ]] && rm "$line"
echo
done 3<filelist
Если нажата ЛЮБАЯ клавиша, кроме клавиши "y" (только нижний регистр), файл не будет удален. Нет необходимости нажимать return после клавиши (отсюда и команда echo для отправки новой строки на дисплей). Обратите внимание, что команда "read" POSIX bash не поддерживает параметр -u, поэтому необходимо искать обходной путь.
Это не совсем "спрашивать да или нет", а просто взломать: псевдоним hg push ...
не для hgpushrepo
но hgpushrepoconfirmedpush
и к тому времени, когда я смогу разобрать все это, левый мозг сделал логичный выбор.