Mejor forma de aceptar variaciones de 'Sí' desde un indicador de comandos de shell

27

Las pruebas de usabilidad de un script de shell que escribí descubrieron que las personas tenían diferentes expectativas sobre cómo responder una pregunta que esperaba un "sí" como respuesta. Ver variaciones en el siguiente código de ejemplo.

¿Seguramente debe haber una mejor manera de lo que se me ocurrió? ¿Cuál es su forma legible y más corta de esto?

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
fuente
2
Votado para cerrar. Si bien estoy interesado en la pregunta, probablemente sea más una cuestión de programación, por lo que debería estar en SO.
phunehehe
Una respuesta de programación podría ser algo así como Bash: compruebe si existe un elemento de matriz
phunehehe
3
@phunehehe: No estoy de acuerdo con pasar a SO, no solo porque tenemos un historial de aceptación de programación de shell, sino también porque no se trata solo de cómo hacerlo, sino también de cuál debería ser la especificación.
Gilles 'SO- deja de ser malvado'
44
Escribí un guión muy parecido a eso una vez. Luego, el programa se tradujo al francés y al chino simplificado. Leí la versión en francés y vi que mi mensaje se tradujo a "Enter oui or non" pero, por supuesto, el código todavía quería "Y *" o "N *"
Ben Jackson

Respuestas:

15

Usar a casees algo equivalente pero no perfecto ya que YEse aceptan declaraciones como .

read -p 'Answer this question with yes: ' answer
case "${answer}" in
    [yY]|[yY][eE][sS])
        echo 'Surely this can be written better?' ;;
esac
sakisk
fuente
3
Yo diría que la intención del usuario es bastante clara por 'ye'.
Aeyoun
48

El estándar UNIX proporciona un código de ejemplo para esto usando la localeutilidad :

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

El valor de 'yesexpr' en la POSIXconfiguración regional (y en configuraciones regionales en inglés en sistemas reales) es "^[yY]". Debe interpretarse como una expresión regular extendida. Ver también noexpr.

Aleatorio832
fuente
1
Agradable. Pero parece que soy un idiota. ¿Dónde puedo encontrar una lista de los argumentos que localeconoce? La página de manual en mi cuadro de Mac OS 10.5 no parece tenerlos.
dmckee
Agradable. ¿Podría por favor volver a la fuente?
Aeyoun
3
@dmckee puede hacerlo locale -k LC_MESSAGES(y para el otro LC_whatever), o vea aquí los definidos por el estándar. @Daniel, ¿qué fuente aparte de la página de la utilidad de configuración regional que he vinculado?
Random832
1
Gran respuesta, definitivamente debería ser la aceptada.
jlliagre
6

Mantenerse en bash (o cualquier otro shell si muestra el mensaje de forma independiente):

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

Esto acepta respuestas yncomo sí,  y(con un espacio inicial) como no, y wlkjzuhfodcomo no, lo que puede no ser óptimo pero es coherente con las típicas indicaciones de shell: así es rm -i, find -oky otros lo hacen.

Esto evita todo el problema de la internacionalización: en otros idiomas, necesitaría traducir las respuestas esperadas. No hay un método de shell estándar entonces; puede pasar al diálogo , pero luego su script requerirá que esté instalado (está disponible en muchas distribuciones pero no siempre está instalado de manera predeterminada).

if dialog --yesno "Choose yes" 0 0; then 
Gilles 'SO- deja de ser malvado'
fuente
3

Usualmente uso una función simple:

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

La función solo regresa 0si se ingresa Yo si yse ingresa 1algo más. Se puede usar con if...fi:

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

O simplemente así:

Confirm "Type y" && echo "You typed y"
Chuck Metcalfe
fuente
Quítese el -spara tener una historia visual de lo que se escribió.
Tom Hale
0

Solo modifiqué @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

Prueba

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
fuente