Melhor maneira de aceitar variações de 'Sim' em um prompt de shell

27

O teste de usabilidade de um script de shell que escrevi descobriu que as pessoas tinham expectativas diferentes sobre como responder a uma pergunta que esperava 'sim' como resposta. Veja variações no exemplo de código abaixo.

Certamente deve haver uma maneira melhor do que eu inventei? Qual é a sua forma legível e mais curta sobre isso?

read -p 'Answer this question with yes: ' answer
if [ "$answer" = 'Y'
  -o "$answer" = 'YES'
  -o "$answer" = 'Yes'
  -o "$answer" = 'y'
  -o "$answer" = 'yes'
  -o some-alternate-condition ]; then

  echo 'Surely this can be written better?'
fi
Aeyoun
fonte
2
Votou para fechar. Embora eu esteja interessado na questão, provavelmente é mais uma questão de programação, portanto deve estar no SO.
Phllhehe
A resposta de programação pode ser algo como Bash: Verifique se elemento do array existe
phunehehe
3
@phunehehe: Não concordo em mudar para SO, não apenas porque temos um histórico de aceitar programação de shell, mas também porque não é apenas uma questão de como fazê-lo, mas também uma pergunta sobre qual deve ser a especificação.
Gilles 'SO- stop be evil'
4
Eu escrevi um script muito parecido com isso uma vez. Em seguida, o programa foi traduzido para o francês e chinês simplificado. I desnatado a versão francesa e vi meu alerta foi traduzido para "Enter oui ou non" mas é claro que o código ainda queria "Y *" ou "N *"
Ben Jackson

Respostas:

15

Usar a caseé um tanto equivalente, mas não perfeito, pois declarações como YEsão aceitas.

read -p 'Answer this question with yes: ' answer
case "${answer}" in
    [yY]|[yY][eE][sS])
        echo 'Surely this can be written better?' ;;
esac
sakisk
fonte
3
Eu diria que a intenção do usuário é bastante clara para 'ye'.
Aeyoun
48

O padrão UNIX fornece um exemplo de código para isso usando o localeutilitário :

if printf "%s\n" "$response" | grep -Eq "$(locale yesexpr)"
then
    affirmative processing goes here
else
    non-affirmative processing goes here
fi

O valor para 'yesexpr' no código do POSIXidioma (e nos idiomas inglês em sistemas reais) é "^[yY]". Deve ser interpretado como uma expressão regular estendida. Veja também noexpr.

Random832
fonte
11
Agradável. Mas eu pareço ser um idiota. Onde posso encontrar uma lista dos argumentos que você localeconhece? A página de manual na minha caixa do Mac OS 10.5 parece não ter.
dmckee
Agradável. Poderia, por favor, ligar de volta à fonte?
Aeyoun 22/05
3
@ dmckee você pode fazer locale -k LC_MESSAGES(e para o outro LC_whatever), ou veja aqui os definidos pelo padrão. @ Daniel Qual fonte, além da página do utilitário de localidade que eu vinculei?
Random832
11
Ótima resposta, definitivamente deve ser a aceita.
Jlliagre
6

Permanecendo no bash (ou em qualquer outro shell, se você exibir o prompt independentemente):

case $answer in
  [Yy]*) echo Ok;;
  *) echo "Can't you read? I said to say yes.";;
esac

Este aceita respostas como yncomo Sim,  y(com um espaço inicial) como não, e wlkjzuhfodcomo não, o que pode não ser o ideal, mas é consistente com prompts de shell típicos: é assim rm -i, find -oke outros fazê-lo.

Isso evita toda a questão da internacionalização: em outros idiomas, você precisaria traduzir as respostas esperadas. Não há método shell padrão então; você pode ativar a caixa de diálogo , mas seu script exigirá que seja instalado (está disponível em muitas distribuições, mas nem sempre é instalado por padrão).

if dialog --yesno "Choose yes" 0 0; then 
Gilles 'SO- parar de ser mau'
fonte
3

Eu costumo usar uma função simples:

Confirm() { read -sn 1 -p "$* [Y/N]? "; [[ ${REPLY:0:1} = [Yy] ]]; }

A função apenas retorna 0se You yé inserida e 1se qualquer outra coisa é inserida. Pode ser usado com if...fi:

if Confirm "Type y or n"; then
echo "You typed y"
else
echo "You typed n"
fi

Ou assim:

Confirm "Type y" && echo "You typed y"
Chuck Metcalfe
fonte
Tire o -spara ter uma história visual do que foi digitado.
Tom Hale
0

Apenas re-modificado @faif ans

YesOrNo() {
        while :
        do
                read -p 'Do you want to Continue (yes/no?): ' answer
                case "${answer}" in
                    [yY]|[yY][eE][sS]) exit 0 ;;
                        [nN]|[nN][oO]) exit 1 ;;
                esac
        done
}


if $( YesOrNo ); then
        echo "Ans is yes.. Do something....."
else
        echo "Ans is No... skip.."
fi

Teste

root@ubuntu:~# bash confirm.sh
Do you want to Continue (yes/no?):  # if Blank Enter then ask again
Do you want to Continue (yes/no?):
Do you want to Continue (yes/no?):
Do you want to Continue (yes/no?): no
Ans is No... skip..
root@ubuntu:~# bash confirm.sh
Do you want to Continue (yes/no?):
Do you want to Continue (yes/no?):
Do you want to Continue (yes/no?): ye
Do you want to Continue (yes/no?): yes
Ans is yes.. Do something.....
Rahul Patil
fonte