Meilleure façon d'accepter les variations de «Oui» à partir d'une invite du shell

27

Les tests d'utilisabilité d'un script shell que j'ai écrit ont révélé que les gens avaient des attentes différentes sur la façon de répondre à une question qui attendait «oui» comme réponse. Voir les variations dans l'exemple de code ci-dessous.

Il doit sûrement y avoir un meilleur moyen que ce que j'ai trouvé? Quelle est votre forme lisible et plus courte à ce sujet?

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
la source
2
A voté pour fermer. Bien que je m'intéresse à la question, c'est probablement plus une question de programmation, donc devrait être sur SO.
phunehehe
Une réponse de programmation pourrait être quelque chose comme Bash: Vérifiez si l'élément de tableau existe
phunehehe
3
@phunehehe: Je suis en désaccord avec le passage à SO, non seulement parce que nous avons une histoire d'acceptation de la programmation shell, mais aussi parce que ce n'est pas seulement une question de savoir comment le faire mais aussi une question de ce que la spécification devrait être.
Gilles 'SO- arrête d'être méchant'
4
J'ai écrit un script un peu comme ça une fois. Ensuite, le programme a été traduit en français et en chinois simplifié. J'ai survolé la version française et j'ai vu que mon invite a été traduite en "Entrez oui ou non" mais bien sûr, le code voulait toujours "Y *" ou "N *"
Ben Jackson

Réponses:

15

L'utilisation de a caseest quelque peu équivalente mais pas parfaite car les déclarations comme YEsont acceptées.

read -p 'Answer this question with yes: ' answer
case "${answer}" in
    [yY]|[yY][eE][sS])
        echo 'Surely this can be written better?' ;;
esac
sakisk
la source
3
Je dirais que l'intention de l'utilisateur est assez claire à partir de «vous».
Aeyoun
48

La norme UNIX fournit un exemple de code pour cela à l'aide de l' localeutilitaire :

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

La valeur de 'yesexpr' dans les POSIXparamètres régionaux (et sur les paramètres régionaux anglais sur les systèmes réels) est "^[yY]". Il doit être interprété comme une expression régulière étendue. Voir aussi noexpr.

Aléatoire832
la source
1
Agréable. Mais je semble être un idiot. Où puis-je trouver une liste des arguments localeconnus? La page de manuel sur ma boîte Mac OS 10.5 ne semble pas en avoir.
dmckee
Agréable. Pourriez-vous renvoyer à la source?
Aeyoun
3
@dmckee vous pouvez le faire locale -k LC_MESSAGES(et pour les autres LC_deux que ce soit), ou voir ici pour ceux définis par la norme. @Daniel quelle source autre que la page d'utilité locale que j'ai liée?
Random832
1
Grande réponse, devrait certainement être celle qui est acceptée.
jlliagre
6

Rester dans bash (ou tout autre shell si vous affichez l'invite indépendamment):

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

Cela accepte les réponses comme ynoui,  y(avec un espace initial) comme non et wlkjzuhfodcomme non, ce qui n'est peut-être pas optimal mais est cohérent avec les invites de shell typiques: c'est comme ça rm -i, find -oket d'autres le font.

Cela évite toute la question de l'internationalisation: dans d'autres langues, il faudrait traduire les réponses attendues. Il n'y a donc pas de méthode shell standard; vous pouvez passer à la boîte de dialogue , mais votre script nécessitera son installation (il est disponible dans de nombreuses distributions mais pas toujours installé par défaut).

if dialog --yesno "Choose yes" 0 0; then 
Gilles 'SO- arrête d'être méchant'
la source
3

J'utilise généralement une fonction simple:

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

La fonction retourne simplement 0si You yest entré et 1si autre chose est entré. Il peut être utilisé avec if...fi:

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

Ou tout simplement comme ceci:

Confirm "Type y" && echo "You typed y"
Chuck Metcalfe
la source
Retirez le -spour avoir un historique visuel de ce qui a été tapé.
Tom Hale
0

Juste re-modifié @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

Tester

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
la source