GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo solicito la entrada Sí/No/Cancelar en un script de shell de Linux?

Al menos cinco respuestas para una pregunta genérica.

Dependiendo de

  • compatible con posix:podría funcionar en sistemas pobres con entornos de shell genéricos
  • específico de bash:usando los llamados bashisms

y si quieres

  • pregunta/respuesta simple ``en línea'' (soluciones genéricas)
  • interfaces bastante formateadas, como ncurses o más gráficas usando libgtk o libqt...
  • utilice la potente capacidad de historial de lectura

1. Soluciones genéricas POSIX

Podrías usar el read comando, seguido de if ... then ... else :

printf 'Is this a good question (y/n)? '
read answer
# if echo "$answer" | grep -iq "^y" ;then
if [ "$answer" != "${answer#[Yy]}" ] ;then # this grammar (the #[] operator) means that the variable $answer where any Y or y in 1st position will be dropped if they exist.
    echo Yes
else
    echo No
fi

(Gracias al comentario de Adam Katz:reemplazó la prueba anterior con una que es más portátil y evita una bifurcación:)

POSIX, pero función de tecla única

Pero si no desea que el usuario tenga que presionar Return , podrías escribir:

(Editado: Como sugiere acertadamente @JonathanLeffler, guardar la configuración de stty podría ser mejor que simplemente forzarlos a cuerdo .)

printf 'Is this a good question (y/n)? '
old_stty_cfg=$(stty -g)
stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg # Careful playing with stty
if echo "$answer" | grep -iq "^y" ;then
    echo Yes
else
    echo No
fi

Nota: ¡Esto fue probado bajo sh, bash, ksh, dash y busybox!

Lo mismo, pero esperando explícitamente y o n :

#/bin/sh
printf '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 Yes
else
    echo No
fi

Uso de herramientas dedicadas

Hay muchas herramientas que se construyeron usando libncurses , libgtk , libqt u otras bibliotecas gráficas. Por ejemplo, usando whiptail :

if whiptail --yesno "Is this a good question" 20 60 ;then
    echo Yes
else
    echo No
fi

Dependiendo de su sistema, es posible que deba reemplazar whiptail con otra herramienta similar:

dialog --yesno "Is this a good question" 20 60 && echo Yes

gdialog --yesno "Is this a good question" 20 60 && echo Yes

kdialog --yesno "Is this a good question" 20 60 && echo Yes

donde 20 es la altura del cuadro de diálogo en número de líneas y 60 es el ancho del cuadro de diálogo. Todas estas herramientas tienen casi lo mismo sintaxis.

DIALOG=whiptail
if [ -x /usr/bin/gdialog ] ;then DIALOG=gdialog ; fi
if [ -x /usr/bin/xdialog ] ;then DIALOG=xdialog ; fi
...
$DIALOG --yesno ...

2. Soluciones específicas de Bash

Básico en línea método

read -p "Is this a good question (y/n)? " answer
case ${answer:0:1} in
    y|Y )
        echo Yes
    ;;
    * )
        echo No
    ;;
esac

Prefiero usar case así que incluso podría probar para yes | ja | si | oui si es necesario...

en línea con llave única función

En bash, podemos especificar la longitud de la entrada prevista para el read comando:

read -n 1 -p "Is this a good question (y/n)? " answer

Bajo bash, read el comando acepta un tiempo de espera parámetro, que podría 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. Algunos trucos para herramientas dedicadas

Cuadros de diálogo más sofisticados, más allá de los simples yes - no propósitos:

dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe

Barra de progreso:

dialog --gauge "Filling the tank" 20 60 0 < <(
    for i in {1..100};do
        printf "XXX\n%d\n%(%a %b %T)T progress: %d\nXXX\n" $i -1 $i
        sleep .033
    done
) 

Pequeña demostración:

#!/bin/sh
while true ;do
    [ -x "$(which ${DIALOG%% *})" ] || DIALOG=dialog
    DIALOG=$($DIALOG --menu "Which tool for next run?" 20 60 12 2>&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 .0125
      done | $DIALOG --gauge "Filling the tank" 20 60 0
    $DIALOG --infobox "This is a simple info box\n\nNo action required" 20 60
    sleep 3
    if $DIALOG --yesno  "Do you like this demo?" 20 60 ;then
        AnsYesNo=Yes; else AnsYesNo=No; fi
    AnsInput=$($DIALOG --inputbox "A text:" 20 60 "Text here..." 2>&1 >/dev/tty)
    AnsPass=$($DIALOG --passwordbox "A secret:" 20 60 "First..." 2>&1 >/dev/tty)
    $DIALOG --textbox /etc/motd 20 60
    AnsCkLst=$($DIALOG --checklist "Check some..." 20 60 12 \
        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:" 20 60 12 \
        " -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" 20 60
  done

¿Más muestras? Eche un vistazo a Usar cola de látigo para elegir un dispositivo USB y un selector de almacenamiento extraíble USB:USBKeyChooser

5. Usando el historial de readline

Ejemplo:

#!/bin/bash

set -i
HISTFILE=~/.myscript.history
history -c
history -r

myread() {
    read -e -p '> ' $1
    history -s ${!1}
}
trap 'history -a;exit' 0 1 2 3 6

while myread line;do
    case ${line%% *} in
        exit )  break ;;
        *    )  echo "Doing something with '$line'" ;;
      esac
  done

Esto creará un archivo .myscript.history en tu $HOME directorio, de lo que podría usar los comandos de historial de readline, como Up , Abajo , Ctrl +r y otros.


El método más simple y ampliamente disponible para obtener la entrada del usuario en un indicador de shell es el read dominio. La mejor manera de ilustrar su uso es una simple demostración:

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.";;
    esac
done

Otro método, señalado por Steven Huwig, es el select de Bash. dominio. Aquí está el mismo ejemplo usando select :

echo "Do you wish to install this program?"
select yn in "Yes" "No"; do
    case $yn in
        Yes ) make install; break;;
        No ) exit;;
    esac
done

Con select no necesita desinfectar la entrada:muestra las opciones disponibles y usted escribe un número correspondiente a su elección. También se repite automáticamente, por lo que no es necesario un while true bucle para volver a intentarlo si dan una entrada no válida.

Además, Léa Gris demostró una forma de hacer que el lenguaje de solicitud sea independiente en su respuesta. Adaptar mi primer ejemplo para servir mejor a varios idiomas podría verse así:

set -- $(locale LC_MESSAGES)
yesexpr="$1"; noexpr="$2"; yesword="$3"; noword="$4"

while true; do
    read -p "Install (${yesword} / ${noword})? " yn
    if [[ "$yn" =~ $yesexpr ]]; then make install; exit; fi
    if [[ "$yn" =~ $noexpr ]]; then exit; fi
    echo "Answer ${yesword} / ${noword}."
done

Obviamente, otras cadenas de comunicación permanecen sin traducir aquí (Instalar, Responder) que deberían abordarse en una traducción más completa, pero incluso una traducción parcial sería útil en muchos casos.

Finalmente, consulte la excelente respuesta de F. Hauri.


echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"

Linux
  1. Cómo Navidadizar su Terminal Linux y Shell

  2. Cómo usar una contraseña cifrada en Linux Bash Shell Script

  3. Cómo comparar números y cadenas en Linux Shell Script

  4. ¿Obtener la secuencia de comandos para que se ejecute de nuevo si la entrada es Sí?

  5. Formato de fecha y hora para script o variable de shell de Linux

Cómo ejecutar el comando / secuencia de comandos de Linux Shell en segundo plano

Shell Scripting para principiantes:cómo escribir Bash Scripts en Linux

Cómo almacenar un comando de Linux como una variable en el script de Shell

Cómo ejecutar Shell Script como servicio SystemD en Linux

Linux:¿cómo ejecutar un script en el bloqueo/desbloqueo de la pantalla?

Linux:¿cómo ejecutar un script activado por una entrada de joystick?