Como solicito a entrada Sim / Não / Cancelar em um script de shell do Linux?
1444
Desejo pausar a entrada em um script de shell e solicitar opções ao usuário.
A pergunta padrão Yes, Noou Canceltipo.
Como faço isso em um prompt típico do bash?
Apenas como uma observação: a convenção para prompts é tal que, se você apresentar uma [yn]opção, a que está em maiúscula é o padrão, ou seja, o padrão é [Yn]"yes" e o [yN]"no". Veja ux.stackexchange.com/a/40445/43532
Tyzoid
Qualquer um que venha do ZSH, veja esta resposta para saber como usar o readcomando para prompt
smac89
Respostas:
1619
O método mais simples e amplamente disponível para obter entrada do usuário em um prompt do shell é o readcomando A melhor maneira de ilustrar seu uso é uma demonstração simples:
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
Outro método, apontado por Steven Huwig , é o selectcomando de Bash . Aqui está o mesmo exemplo usando select:
echo "Do you wish to install this program?"
select yn in"Yes""No";docase $yn inYes) make install;break;;No) exit;;esacdone
Com selectvocê, não é necessário limpar a entrada - ela exibe as opções disponíveis e você digita um número correspondente à sua escolha. Também faz loops automaticamente, portanto, não há necessidade de um while trueloop tentar novamente se eles fornecerem entradas inválidas.
Além disso, Léa Gris demonstrou uma maneira de tornar a linguagem de solicitação agnóstica em sua resposta . A adaptação do meu primeiro exemplo para melhor atender a vários idiomas pode ser assim:
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
Obviamente, outras strings de comunicação permanecem sem tradução aqui (Instalação, Resposta), que precisariam ser tratadas em uma tradução mais completa, mas mesmo uma tradução parcial seria útil em muitos casos.
Usando Bash no OS X Leopard, eu mudei exitpara breakmanter-se de fechar a guia quando eu selecionei 'não'.
Trey Piepmeier 02/12/2009
1
Como isso funciona com opções maiores que Sim ou Não? Na cláusula case, você escreve algo como: Instale o programa e não faça nada depois) make install; quebrar;
Shawn
1
@ Shawn Com a leitura, você pode, é claro, usar qualquer padrão glob ou regex suportado pela instrução switch do bash shell. Apenas corresponde ao texto digitado nos seus padrões até encontrar uma correspondência. Usando select , a lista de opções é fornecida ao comando e as exibe ao usuário. Você pode fazer com que os itens da lista sejam longos ou curtos, conforme desejar. Eu recomendo verificar suas páginas de manual para obter informações abrangentes de uso.
Myrddin Emrys
3
por que existe um breakno selectse não houver loop?
Jayen
1
@akostadinov Eu realmente deveria ler mais meu histórico de edições. Você está correto, eu estou errado, e apresentei um bug seguindo o conselho de Jayan, hah. O bug foi corrigido mais tarde, mas as edições estavam tão distantes que nem me lembro de alterá-lo.
Myrddin Emrys #
527
Pelo menos cinco respostas para uma pergunta genérica.
Dependendo
posix compatível: poderia funcionar em sistemas ruins com genéricos Concha ambientes
#/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
Usando ferramentas dedicadas
Existem muitas ferramentas que foram construídos usando libncurses, libgtk, libqtou outras bibliotecas gráficas. Por exemplo, usando whiptail:
if whiptail --yesno "Is this a good question"2060;then
echo Yeselse
echo Nofi
Dependendo do seu sistema, pode ser necessário substituí-lo whiptailpor outra ferramenta similar:
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
onde 20é a altura da caixa de diálogo em número de linhas e a 60largura da caixa de diálogo. Todas essas ferramentas têm quase a mesma sintaxe.
read -p "Is this a good question (y/n)? " answer
case ${answer:0:1}in
y|Y )
echo Yes;;*)
echo No;;esac
Eu prefiro usar casepara testar yes | ja | si | ouise necessário ...
de acordo com o recurso de tecla única
Sob bash, podemos especificar o comprimento da entrada pretendida para o readcomando:
read -n 1-p "Is this a good question (y/n)? " answer
Em bash, o readcomando aceita um parâmetro de tempo limite , que pode ser útil.
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. Alguns truques para ferramentas dedicadas
Caixas de diálogo mais sofisticadas, além de yes - nopropósitos simples :
dialog --menu "Is this a good question"206012 y Yes n No m Maybe
Barra de progresso:
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)
Pequena demonstração:
#!/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
Note-se que sttyfornece a -gopção de uso: old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty". Isso restaura a configuração exatamente como foi encontrada, que pode ou não ser a mesma que stty -sane.
Jonathan Leffler
3
read answerinterpretará as barras invertidas antes dos espaços e das linhas e, de outra forma, as removerá, o que raramente é planejado. Use em read -r answervez disso, conforme SC2162 .
vlfig 31/03
1
O método "Usando o histórico da readline" é tão inapropriado para a pergunta do OP. Estou feliz que você tenha incluído de qualquer maneira. Eu tenho dezenas de scripts muito mais complicados que pretendo atualizar com esse padrão!
Bruno Brosky # 19/17
5
Você pode usar o casePOSIX e o bash (use uma condição curinga em vez de uma substring do bash:) case $answer in; [Yy]* ) echo Yes ;;, mas prefiro usar uma instrução condicional, favorecendo [ "$answer" != "${answer#[Yy]}" ]a sua echo "$answer" | grep -iq ^y. É mais portátil (alguns greps não-GNU não implementam -qcorretamente) e não possui a chamada de sistema. ${answer#[Yy]}usa expansão de parâmetro para remover You ydo início de $answer, causando uma desigualdade quando uma delas está presente. Isso funciona em qualquer shell POSIX (traço, ksh, bash, zsh, busybox, etc).
23418 Adam
1
@CarterPape Sim, isso foi uma piada! Mas nesta resposta detalhada, você pode encontrar muitas dicas (o segundo ponto apresenta pelo menos três métodos diferentes)! E ... há aproximadamente 5 anos, você é o primeiro a contar sobre o meu método de contagem! ;-))
F. Hauri
349
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
Não concordo, porque ele implementa apenas uma parte da funcionalidade da caixa de diálogo 'Sim, Não, Cancelar' no DOS. A parte que ele falha na implementação é a verificação de entrada ... repetindo até que uma resposta válida seja recebida.
Myrddin Emrys #
1
(O título da pergunta original era "Como eu pronta para a entrada em um script shell Linux?")
Pistos
8
Mas a descrição original da pergunta permanece inalterada e sempre solicita uma resposta para um prompt Sim / Não / Cancelar. O título foi atualizado para ser mais claro que o original, mas a descrição da pergunta sempre foi clara (na minha opinião).
Myrddin Emrys
165
Você pode usar o comando de leitura interno; Use a -popção para solicitar ao usuário uma pergunta.
Desde o BASH4, agora você pode usar -ipara sugerir uma resposta:
read -e -p "Enter the path to the file: "-i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(Mas lembre-se de usar a opção "readline" -epara permitir a edição de linha com as teclas de seta)
Se você deseja uma lógica "sim / não", pode fazer algo assim:
read -e -p "
List the content of your home dir ? [Y/n] " YN
[[ $YN =="y"|| $YN =="Y"|| $YN ==""]]&& ls -la ~/
Note-se que FILEPATHé o nome da variável que você escolheu e é definido com a resposta no prompt de comando. Portanto, se você executasse vlc "$FILEPATH", por exemplo, vlcabriria esse arquivo.
Ken Sharp
Qual é o benefício do -esegundo exemplo (simples sim / não)?
JBallin
Alguma razão para usar em -e -pvez de -ep?
JBallin
1
Sem o -esinalizador / opção, você pode (dependendo da implementação) não conseguir digitar "y" e depois mudar de idéia e substituí-lo por um "n" (ou qualquer outra coisa a esse respeito); Ao documentar um comando, listar as opções separadamente é melhor para legibilidade / clareza, entre outros motivos.
+1 Solução genialmente simples. A única coisa: Isto irá pedir e promt e pronta ... até que você adicione um exitinterior :)
kaiser
5
(kaiser: Para quebrar a partir dele, basta digitar o EOT: Ctrl-DMas é claro, o código real usando ele vai precisar de uma pausa ou uma saída no corpo..)
Zorawar
12
Isso não vai permitir que você digite y ou n, though.You escolher inserindo 1 2 ou 3.
djjeck
3
exitvai sair do script todos juntos, breaksó vai sair do loop você está no (se você estiver em um whileou casecircular)
wranvaud
57
read -p "Are you alright? (y/n) " RESP
if["$RESP"="y"];then
echo "Glad to hear it"else
echo "You need more bash programming"fi
Coloque quatro espaços no início de cada linha para preservar a formatação do código.
Jouni K. Seppänen
10
Por que fornecemos 'y' e 'n' como parâmetros para indagar () se as opções de maiúsculas e minúsculas são codificadas? Isso é apenas pedir mau uso. Como parâmetros fixos, não são alteráveis, o eco na linha 2 deve ler: echo -n "$ 1 [S / N]?" Eles não podem ser alterados, portanto não devem ser fornecidos.
Myrddin Emrys
1
@MyrddinEmrys Você poderia, por favor, elaborar seu comentário? Ou poste um link para um artigo ou algumas palavras-chave para que eu possa fazer pesquisas por conta própria.
Mateusz Piotrowski 26/03
4
@MateuszPiotrowski A resposta foi editada e melhorada desde que fiz o meu comentário. Você pode clicar no link "editado em 23 de dezembro" acima para visualizar todas as versões anteriores desta resposta. Em 2008, o código era bem diferente.
Myrddin Emrys 27/03
27
Você quer:
Comandos internos do Bash (ou seja, portáteis)
Verifique TTY
Resposta padrão
Tempo esgotado
Pergunta colorida
Snippet
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
@Jav o eco imprime uma nova linha após sua resposta. Sem ele, a próxima coisa a ser impressa aparecerá imediatamente após a sua resposta na mesma linha. Tente remover o echopara ver por si mesmo.
Dennis
13
Para obter uma boa caixa de entrada semelhante a ncurses, use a caixa de diálogo de comando assim:
#!/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
O pacote de diálogo é instalado por padrão pelo menos com o SUSE Linux. Parece:
yap, -e-inão funcionam no sh (Bourne shell), mas a questão é o bash marcado especificamente ..
Jahid
12
Você pode usar o padrão REPLYem a read, converter em minúscula e comparar com um conjunto de variáveis com uma expressão.
O script também suporta 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
É possível manipular uma escolha "Sim / Não" com reconhecimento de localidade em um shell POSIX; usando as entradas da LC_MESSAGEScategoria localidade, o witch fornece padrões RegEx prontos para corresponder a uma entrada e cadeias de caracteres localizadas Sim Não.
#!/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
As palavras-chave yesstre nostrlocale e os itens YESSTRe NOSTRlanginfo foram usados anteriormente para corresponder às respostas afirmativas e negativas do usuário. Em POSIX.1-2008, o yesexpr, noexpr, YESEXPR, e NOEXPRexpressões regulares estendidas substituíram-los. Os aplicativos devem usar os recursos gerais de mensagens com base no código do idioma para emitir mensagens de prompt que incluem respostas desejadas de amostra.
Como alternativa, use localidades da maneira Bash:
Adoro a adição de uma opção independente de idioma. Bem feito.
Myrddin Emrys
1
Infelizmente, o POSIX especifica apenas os dois primeiros (yesexpr e noexpr). No Ubuntu 16, yesstr e nostr estão vazios.
Urhixidur 9/01
1
Mas espere! Há notícias piores! As expressões da instrução bash case não são regulares, são expressões de nome de arquivo. Portanto, yesexpr e noexpr do Ubuntu 16 ("^ [yY]. *" E "^ [nN]. *", Respectivamente) falharão totalmente por causa do período incorporado. Em uma expressão regular, ". *" Significa "qualquer caractere que não seja de nova linha, zero ou mais vezes". Mas em uma declaração de caso, é um literal "." seguido por qualquer número de caracteres.
Urhixidur 9/01
1
Finalmente, o melhor que pode ser feito com yesexpre noexprem um ambiente shell é usá-lo na correspondência RegEx específica do Bashif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
Léa Gris
10
Somente pressionamento de tecla único
Aqui está uma abordagem mais longa, mas reutilizável e modular:
Retorna 0= sim e 1= não
Não é necessário pressionar pressionar - apenas um único caractere
Pode pressionar enterpara aceitar a opção padrão
Pode desativar a opção padrão para forçar uma seleção
Funciona para ambos zshe bash.
O padrão é "não" ao pressionar enter
Observe que o Ncapital é maiúsculo. Aqui, enter é pressionado, aceitando o padrão:
Acima, eu apenas pressionei enter, então o comando foi executado.
Nenhum padrão ativado enter- requer youn
$ 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
Aqui, 1ou false foi retornado. Observe que, com esta função de nível inferior, você precisará fornecer seu próprio [y/n]?prompt.
Código
# 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}
Quando eu testei esse script, em vez do outut acima que eu tenho, Show dangerous command [y/N]? [y/n]?eShow dangerous command [Y/n]? [y/n]?
Ilias Karim
Obrigado @IliasKarim, consertei isso agora.
Tom Hale
9
Desculpe por postar em um post tão antigo. Algumas semanas atrás, eu estava enfrentando um problema semelhante, no meu caso, precisava de uma solução que também funcionasse dentro de um script de instalação online, por exemplo:curl -Ss https://raw.github.com/_____/installer.sh | bash
Usar read yesno < /dev/ttyfunciona bem para mim:
echo -n "These files will be uploaded. Is this ok? (y/n) "
read yesno </dev/tty
if["x$yesno"="xy"];then# Yeselse# Nofi
Uma parte importante disso é a validação de entrada. Eu acho que adaptar meu primeiro exemplo para aceitar ttyentradas como você teria feito também para você, e também ter recebido loop de entrada ruim (imagine alguns caracteres no buffer; seu método forçaria o usuário a sempre escolher não).
Myrddin Emrys
7
Notei que ninguém postou uma resposta mostrando o menu de eco de várias linhas para uma entrada tão simples do usuário, então aqui está a minha tentativa:
Uma maneira simples de fazer isso é com xargs -pou gnu parallel --interactive.
Eu gosto do comportamento do xargs um pouco melhor para isso, porque ele executa cada comando imediatamente após o prompt, como outros comandos unix interativos, em vez de coletar os yesses para executar no final. (Você pode pressionar Ctrl-C depois de passar pelos que deseja.)
Não é ruim, mas xargs --interactiveé limitado a sim ou não. Contanto que seja tudo o que você precisa, isso pode ser suficiente, mas minha pergunta original deu um exemplo com três resultados possíveis. Eu realmente gosto que seja fácil de usar; muitos cenários comuns se beneficiariam de sua capacidade de ser canalizado.
Myrddin Emrys
Eu vejo. Meu pensamento era que "cancel" significava simplesmente interromper toda a execução adicional, compatível com Ctrl-C, mas se você precisar fazer algo mais complexo no cancelamento (ou não), isso não será suficiente.
21415 Joshua Goldberg #
3
Como amigo de um comando de uma linha, usei o seguinte:
Você pode esclarecer o uso da variável prompt? Parece-me que ele foi apagado após o revestimento, então como você usa a linha para fazer alguma coisa?
Myrddin Emrys
O prompt é apagado após o loop while. Porque eu quero que a variável prompt seja inicializada posteriormente (já que estou usando a instrução com mais frequência). Ter essa linha em um shell-script só continuará se y | Y for digitado e sairá se n | N for digitado ou repita, solicitando entrada para todo o resto.
ccDict
3
Eu usei a casedeclaração algumas vezes nesse cenário, usar a declaração de caso é uma boa maneira de fazer isso. Um whileloop, que ecapsula o casebloco, que utiliza uma condição booleana, pode ser implementado para manter ainda mais controle do programa e atender a muitos outros requisitos. Após todas as condições terem sido atendidas, breakpode ser usado um que passará o controle de volta para a parte principal do programa. Além disso, para atender a outras condições, é claro que instruções condicionais podem ser adicionadas para acompanhar as estruturas de controle: caseinstrução e whileloop possível .
Exemplo de uso de uma casedeclaração para atender sua solicitação
#! /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
Isso parece complexo e frágil. Que tal apenasyn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure
triplee
2
Em resposta a outros:
Você não precisa especificar maiúsculas e minúsculas no BASH4, basta usar o ',,' para fazer uma var minúscula. Também não gosto de colocar código dentro do bloco de leitura, obter o resultado e lidar com ele fora do bloco de leitura IMO. Inclua também um 'q' para sair do IMO. Por fim, por que digite 'yes' basta usar -n1 e pressionar y.
Exemplo: o usuário pode pressionar y / ne também q para sair.
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
Na maioria das vezes, nesses cenários, você precisa continuar executando o script até que o usuário continue digitando "yes" e só precise parar quando o usuário digitar "no". O trecho abaixo ajudaria você a conseguir isso!
#!/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]
opção, a que está em maiúscula é o padrão, ou seja, o padrão é[Yn]
"yes" e o[yN]
"no". Veja ux.stackexchange.com/a/40445/43532read
comando para promptRespostas:
O método mais simples e amplamente disponível para obter entrada do usuário em um prompt do shell é o
read
comando A melhor maneira de ilustrar seu uso é uma demonstração simples:Outro método, apontado por Steven Huwig , é o
select
comando de Bash . Aqui está o mesmo exemplo usandoselect
:Com
select
você, não é necessário limpar a entrada - ela exibe as opções disponíveis e você digita um número correspondente à sua escolha. Também faz loops automaticamente, portanto, não há necessidade de umwhile true
loop tentar novamente se eles fornecerem entradas inválidas.Além disso, Léa Gris demonstrou uma maneira de tornar a linguagem de solicitação agnóstica em sua resposta . A adaptação do meu primeiro exemplo para melhor atender a vários idiomas pode ser assim:
Obviamente, outras strings de comunicação permanecem sem tradução aqui (Instalação, Resposta), que precisariam ser tratadas em uma tradução mais completa, mas mesmo uma tradução parcial seria útil em muitos casos.
Por fim, confira a excelente resposta de F. Hauri .
fonte
exit
parabreak
manter-se de fechar a guia quando eu selecionei 'não'.break
noselect
se não houver loop?Pelo menos cinco respostas para uma pergunta genérica.
Dependendo
e se você quiser
1. Soluções genéricas POSIX
Você pode usar o
read
comando, seguido porif ... then ... else
:(Obrigado ao comentário de Adam Katz : Substituído o teste acima por um que seja mais portátil e evite um garfo :)
POSIX, mas recurso de chave única
Mas se você não quiser que o usuário acerte Return, escreva:
( Editado: como o @JonathanLeffler sugere, salvar a configuração do stty pode ser melhor do que simplesmente forçá-lo a sane .)
Nota: Isso foi testado emsh, bater, ksh, traço e busybox!
Mesmo, mas esperando explicitamente por you n:
Usando ferramentas dedicadas
Existem muitas ferramentas que foram construídos usando
libncurses
,libgtk
,libqt
ou outras bibliotecas gráficas. Por exemplo, usandowhiptail
:Dependendo do seu sistema, pode ser necessário substituí-lo
whiptail
por outra ferramenta similar:onde
20
é a altura da caixa de diálogo em número de linhas e a60
largura da caixa de diálogo. Todas essas ferramentas têm quase a mesma sintaxe.2. Soluções específicas do Bash
Método básico em linha
Eu prefiro usar
case
para testaryes | ja | si | oui
se necessário ...de acordo com o recurso de tecla única
Sob bash, podemos especificar o comprimento da entrada pretendida para o
read
comando:Em bash, o
read
comando aceita um parâmetro de tempo limite , que pode ser útil.3. Alguns truques para ferramentas dedicadas
Caixas de diálogo mais sofisticadas, além de
yes - no
propósitos simples :Barra de progresso:
Pequena demonstração:
Mais amostra? Veja Usando o chicote para escolher o dispositivo USB e o seletor de armazenamento removível USB: USBKeyChooser
5. Usando o histórico da readline
Exemplo:
Isto irá criar um arquivo
.myscript.history
em seu$HOME
diretório, que você pode usar comandos de história do readline, como Up, Down, Ctrl+ routros e.fonte
stty
fornece a-g
opção de uso:old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty"
. Isso restaura a configuração exatamente como foi encontrada, que pode ou não ser a mesma questty -sane
.read answer
interpretará as barras invertidas antes dos espaços e das linhas e, de outra forma, as removerá, o que raramente é planejado. Use emread -r answer
vez disso, conforme SC2162 .case
POSIX e o bash (use uma condição curinga em vez de uma substring do bash:)case $answer in; [Yy]* ) echo Yes ;;
, mas prefiro usar uma instrução condicional, favorecendo[ "$answer" != "${answer#[Yy]}" ]
a suaecho "$answer" | grep -iq ^y
. É mais portátil (alguns greps não-GNU não implementam-q
corretamente) e não possui a chamada de sistema.${answer#[Yy]}
usa expansão de parâmetro para removerY
ouy
do início de$answer
, causando uma desigualdade quando uma delas está presente. Isso funciona em qualquer shell POSIX (traço, ksh, bash, zsh, busybox, etc).fonte
Você pode usar o comando de leitura interno; Use a
-p
opção para solicitar ao usuário uma pergunta.Desde o BASH4, agora você pode usar
-i
para sugerir uma resposta:(Mas lembre-se de usar a opção "readline"
-e
para permitir a edição de linha com as teclas de seta)Se você deseja uma lógica "sim / não", pode fazer algo assim:
fonte
FILEPATH
é o nome da variável que você escolheu e é definido com a resposta no prompt de comando. Portanto, se você executassevlc "$FILEPATH"
, por exemplo,vlc
abriria esse arquivo.-e
segundo exemplo (simples sim / não)?-e -p
vez de-ep
?-e
sinalizador / opção, você pode (dependendo da implementação) não conseguir digitar "y" e depois mudar de idéia e substituí-lo por um "n" (ou qualquer outra coisa a esse respeito); Ao documentar um comando, listar as opções separadamente é melhor para legibilidade / clareza, entre outros motivos.O Bash selecionou para esse fim.
fonte
exit
interior :)Ctrl-D
Mas é claro, o código real usando ele vai precisar de uma pausa ou uma saída no corpo..)exit
vai sair do script todos juntos,break
só vai sair do loop você está no (se você estiver em umwhile
oucase
circular)fonte
Aqui está uma coisa que eu montei:
Sou iniciante, então leve isso com um pouco de sal, mas parece funcionar.
fonte
case $yn in
paracase ${yn:-$2} in
, em seguida, você pode usar o segundo argumento como o valor padrão, Y ou N.case $yn
paracase "${yn:-Y}"
ter sim como padrãofonte
Você quer:
Snippet
Explicações
[[ -t 0 ]] && read ...
=> Chamar comandoread
se TTYread -n 1
=> Aguarde um caractere$'\e[1;32m ... \e[0m '
=> Imprimir em verde(o verde é bom porque legível nos fundos branco / preto)
[[ $do_xxxx =~ ^(y|Y|)$ ]]
=> bash regexTempo limite => A resposta padrão é Não
fonte
A maneira mais fácil de conseguir isso com o menor número de linhas é a seguinte:
Este
if
é apenas um exemplo: você decide como lidar com essa variável.fonte
Use o
read
comando:e então todas as outras coisas que você precisa
fonte
Esta solução lê um único caractere e chama uma função em uma resposta sim.
fonte
echo
para ver por si mesmo.Para obter uma boa caixa de entrada semelhante a ncurses, use a caixa de diálogo de comando assim:
O pacote de diálogo é instalado por padrão pelo menos com o SUSE Linux. Parece:
fonte
A
-e
opção permite que o usuário edite a entrada usando as teclas de seta.Se você deseja usar uma sugestão como entrada:
-i
A opção imprime uma entrada sugestiva.fonte
-e
-i
não funcionam no sh (Bourne shell), mas a questão é o bash marcado especificamente ..Você pode usar o padrão
REPLY
em aread
, converter em minúscula e comparar com um conjunto de variáveis com uma expressão.O script também suporta
ja
/si
/oui
fonte
É possível manipular uma escolha "Sim / Não" com reconhecimento de localidade em um shell POSIX; usando as entradas da
LC_MESSAGES
categoria localidade, o witch fornece padrões RegEx prontos para corresponder a uma entrada e cadeias de caracteres localizadas Sim Não.EDIT: Como @Urhixidur mencionado em seu comentário :
Consulte: https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06
Como alternativa, use localidades da maneira Bash:
A resposta é correspondida usando os regexps fornecidos pelo ambiente de localidade.
Para converter as mensagens restantes, use
bash --dump-po-strings scriptname
para gerar as seqüências de caracteres po para localização:fonte
yesexpr
enoexpr
em um ambiente shell é usá-lo na correspondência RegEx específica do Bashif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
Somente pressionamento de tecla único
Aqui está uma abordagem mais longa, mas reutilizável e modular:
0
= sim e1
= nãozsh
ebash
.O padrão é "não" ao pressionar enter
Observe que o
N
capital é maiúsculo. Aqui, enter é pressionado, aceitando o padrão:Observe também que
[y/N]?
foi anexado automaticamente. O "não" padrão é aceito, então nada é ecoado.Solicite novamente até que uma resposta válida seja fornecida:
O padrão é "yes" ao pressionar enter
Observe que o
Y
é maiúsculo:Acima, eu apenas pressionei enter, então o comando foi executado.
Nenhum padrão ativado enter- requer
y
oun
Aqui,
1
ou false foi retornado. Observe que, com esta função de nível inferior, você precisará fornecer seu próprio[y/n]?
prompt.Código
fonte
Show dangerous command [y/N]? [y/n]?
eShow dangerous command [Y/n]? [y/n]?
Desculpe por postar em um post tão antigo. Algumas semanas atrás, eu estava enfrentando um problema semelhante, no meu caso, precisava de uma solução que também funcionasse dentro de um script de instalação online, por exemplo:
curl -Ss https://raw.github.com/_____/installer.sh | bash
Usar
read yesno < /dev/tty
funciona bem para mim:Espero que isso ajude alguém.
fonte
tty
entradas como você teria feito também para você, e também ter recebido loop de entrada ruim (imagine alguns caracteres no buffer; seu método forçaria o usuário a sempre escolher não).Notei que ninguém postou uma resposta mostrando o menu de eco de várias linhas para uma entrada tão simples do usuário, então aqui está a minha tentativa:
Este método foi publicado na esperança de que alguém possa achar útil e que economiza tempo.
fonte
Versão de múltipla escolha:
Exemplo:
Ele será definido
REPLY
comoy
(dentro do script).fonte
Eu sugiro que você use o diálogo ...
é simples e fácil de usar, há também uma versão do gnome chamada gdialog que usa exatamente os mesmos parâmetros, mas mostra o estilo da GUI no X.
fonte
Inspirado pelas respostas de @Mark e @Myrddin, criei esta função para um prompt universal
use-o assim:
fonte
mais genérico seria:
fonte
Uma maneira simples de fazer isso é com
xargs -p
ou gnuparallel --interactive
.Eu gosto do comportamento do xargs um pouco melhor para isso, porque ele executa cada comando imediatamente após o prompt, como outros comandos unix interativos, em vez de coletar os yesses para executar no final. (Você pode pressionar Ctrl-C depois de passar pelos que deseja.)
por exemplo,
fonte
xargs --interactive
é limitado a sim ou não. Contanto que seja tudo o que você precisa, isso pode ser suficiente, mas minha pergunta original deu um exemplo com três resultados possíveis. Eu realmente gosto que seja fácil de usar; muitos cenários comuns se beneficiariam de sua capacidade de ser canalizado.Como amigo de um comando de uma linha, usei o seguinte:
Longform escrito, funciona assim:
fonte
Eu usei a
case
declaração algumas vezes nesse cenário, usar a declaração de caso é uma boa maneira de fazer isso. Umwhile
loop, que ecapsula ocase
bloco, que utiliza uma condição booleana, pode ser implementado para manter ainda mais controle do programa e atender a muitos outros requisitos. Após todas as condições terem sido atendidas,break
pode ser usado um que passará o controle de volta para a parte principal do programa. Além disso, para atender a outras condições, é claro que instruções condicionais podem ser adicionadas para acompanhar as estruturas de controle:case
instrução ewhile
loop possível .Exemplo de uso de uma
case
declaração para atender sua solicitaçãofonte
Sim / Não / Cancelar
Função
Uso
Confirme com entrada limpa do usuário
Função
Uso
fonte
fonte
yn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure
Em resposta a outros:
Você não precisa especificar maiúsculas e minúsculas no BASH4, basta usar o ',,' para fazer uma var minúscula. Também não gosto de colocar código dentro do bloco de leitura, obter o resultado e lidar com ele fora do bloco de leitura IMO. Inclua também um 'q' para sair do IMO. Por fim, por que digite 'yes' basta usar -n1 e pressionar y.
Exemplo: o usuário pode pressionar y / ne também q para sair.
fonte
Na maioria das vezes, nesses cenários, você precisa continuar executando o script até que o usuário continue digitando "yes" e só precise parar quando o usuário digitar "no". O trecho abaixo ajudaria você a conseguir isso!
fonte