GNU/Linux >> Tutoriels Linux >  >> Linux

Comment puis-je demander une entrée Oui/Non/Annuler dans un script shell Linux ?

Au moins cinq réponses pour une question générique.

Selon

  • conforme posix :peut fonctionner sur des systèmes médiocres avec des environnements shell génériques
  • spécifique à bash :utilisation des soi-disant bashismes

et si vous voulez

  • question/réponse simple "en ligne" (solutions génériques)
  • interfaces joliment formatées, comme ncurses ou plus graphiques utilisant libgtk ou libqt...
  • utiliser une puissante capacité d'historique de lecture

1. Solutions génériques POSIX

Vous pouvez utiliser le read commande, suivi 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

(Merci au commentaire d'Adam Katz :Remplacé le test ci-dessus par un test plus portable et qui évite un fork :)

POSIX, mais fonctionnalité clé unique

Mais si vous ne voulez pas que l'utilisateur ait à appuyer sur Retour , vous pourriez écrire :

(Modifié : Comme le suggère à juste titre @JonathanLeffler, économiser la configuration de stty pourrait être meilleure que de simplement les forcer à sain .)

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

Remarque : Cela a été testé sous sh, bash, ksh, dash et busybox !

Idem, mais attend explicitement y ou 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

Utiliser des outils dédiés

Il existe de nombreux outils qui ont été construits en utilisant libncurses , libgtk , libqt ou d'autres bibliothèques graphiques. Par exemple, en utilisant whiptail :

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

Selon votre système, vous devrez peut-être remplacer whiptail avec un autre outil similaire :

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

20 est la hauteur de la boîte de dialogue en nombre de lignes et 60 est la largeur de la boîte de dialogue. Ces outils ont tous presque la même chose syntaxe.

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

2. Solutions spécifiques à Bash

De base en ligne méthode

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

Je préfère utiliser case donc je pourrais même tester pour yes | ja | si | oui si besoin...

en ligne avec clé unique fonctionnalité

Sous bash, nous pouvons spécifier la longueur de l'entrée prévue pour le read commande :

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

Sous bash, read la commande accepte un timeout paramètre, ce qui pourrait être utile.

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. Quelques astuces pour les outils dédiés

Des boîtes de dialogue plus sophistiquées, au-delà du simple yes - no fins :

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

Barre de progression :

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
) 

Petite démo :

#!/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

Plus d'échantillons ? Jetez un œil à Utilisation de Whiptail pour choisir un périphérique USB et un sélecteur de stockage amovible USB :USBKeyChooser

5. Utiliser l'historique de readline

Exemple :

#!/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

Cela créera un fichier .myscript.history dans votre $HOME répertoire, que vous pouvez utiliser les commandes d'historique de readline, comme Up , Bas , Ctrl +r et autres.


La méthode la plus simple et la plus largement disponible pour obtenir une entrée utilisateur à une invite du shell est le read commande. La meilleure façon d'illustrer son utilisation est une simple démonstration :

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

Une autre méthode, soulignée par Steven Huwig, est le select de Bash commande. Voici le même exemple en utilisant 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

Avec select vous n'avez pas besoin de nettoyer l'entrée - elle affiche les choix disponibles et vous tapez un nombre correspondant à votre choix. Il boucle également automatiquement, il n'y a donc pas besoin d'un while true boucle pour réessayer s'ils donnent une entrée invalide.

De plus, Léa Gris a démontré un moyen de rendre la langue de la requête agnostique dans sa réponse. L'adaptation de mon premier exemple pour mieux servir plusieurs langues pourrait ressembler à ceci :

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

Évidemment, d'autres chaînes de communication restent non traduites ici (installation, réponse) qui devraient être traitées dans une traduction plus complète, mais même une traduction partielle serait utile dans de nombreux cas.

Enfin, veuillez consulter l'excellente réponse de F. Hauri.


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

Linux
  1. Formater la date et l'heure pour le script ou la variable du shell Linux

  2. Masquer l'entrée utilisateur sur le terminal dans le script Linux

  3. Comment rechercher des fichiers à l'aide de regex dans le script shell Linux

  4. Comment écrire un script de réponse oui pour installer des programmes ?

  5. Script shell Linux pour la sauvegarde de la base de données

Comment exécuter une commande / un script Linux Shell en arrière-plan

Shell Scripting pour les débutants - Comment écrire des scripts Bash sous Linux

Comment stocker une commande Linux en tant que variable dans un script shell

Comment exécuter un script Shell en tant que service SystemD sous Linux

Linux - Comment exécuter un script déclenché par une entrée de joystick ?

Comment insérer une nouvelle ligne dans le script shell Linux ?