GNU/Linux >> Linux Esercitazione >  >> Linux

Come posso richiedere l'input Sì/No/Annulla in uno script della shell di Linux?

Almeno cinque risposte per una domanda generica.

A seconda di

  • conforme a posix:potrebbe funzionare su sistemi scadenti con ambienti shell generici
  • specifico per bash:utilizzo dei cosiddetti bashismi

e se vuoi

  • semplice domanda/risposta ``in linea'' (soluzioni generiche)
  • interfacce piuttosto formattate, come ncurses o più grafiche usando libgtk o libqt...
  • usa la potente funzionalità della cronologia di readline

1. Soluzioni generiche POSIX

Potresti usare il read comando, seguito da 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

(Grazie al commento di Adam Katz:Sostituito il test sopra con uno che è più portatile ed evita un fork:)

POSIX, ma un'unica caratteristica chiave

Ma se non vuoi che l'utente debba premere Invio , potresti scrivere:

(Modificato: Come suggerisce giustamente @JonathanLeffler, il risparmio la configurazione di stty potrebbe essere migliore del semplice forzarli a sane .)

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: Questo è stato testato con sh, bash, ksh, dash e busybox!

Lo stesso, ma aspettando esplicitamente 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

Utilizzando strumenti dedicati

Ci sono molti strumenti che sono stati creati usando libncurses , libgtk , libqt o altre librerie grafiche. Ad esempio, utilizzando whiptail :

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

A seconda del tuo sistema, potresti dover sostituire whiptail con un altro strumento simile:

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

dove 20 è l'altezza della finestra di dialogo in numero di righe e 60 è la larghezza della finestra di dialogo. Tutti questi strumenti hanno quasi lo stesso sintassi.

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

2. Soluzioni specifiche per Bash

Base in linea metodo

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

Preferisco usare case quindi potrei anche testare per yes | ja | si | oui se necessario...

in fila con chiave singola funzionalità

Sotto bash, possiamo specificare la lunghezza dell'input previsto per read comando:

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

Sotto bash, read comando accetta un timeout parametro, che potrebbe essere 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. Alcuni trucchi per gli strumenti dedicati

Finestre di dialogo più sofisticate, oltre il semplice yes - no finalità:

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

Barra di avanzamento:

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
) 

Piccola demo:

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

Altri campioni? Dai un'occhiata a Utilizzo di whiptail per la scelta del dispositivo USB e del selettore di archiviazione rimovibile USB:USBKeyChooser

5. Utilizzo della cronologia di readline

Esempio:

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

Questo creerà un file .myscript.history nel tuo $HOME directory, quindi potresti usare i comandi della cronologia di readline, come Up , Giù , Ctrl +r e altri.


Il metodo più semplice e ampiamente disponibile per ottenere l'input dell'utente al prompt della shell è il read comando. Il modo migliore per illustrare il suo utilizzo è una semplice dimostrazione:

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

Un altro metodo, indicato da Steven Huwig, è il select di Bash comando. Ecco lo stesso esempio 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 non è necessario disinfettare l'input:mostra le scelte disponibili e digiti un numero corrispondente alla tua scelta. Si ripete anche automaticamente, quindi non c'è bisogno di un while true loop per riprovare se danno un input non valido.

Inoltre, Léa Gris ha mostrato un modo per rendere agnostica la lingua della richiesta nella sua risposta. Adattare il mio primo esempio per servire meglio più lingue potrebbe assomigliare a questo:

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

Ovviamente altre stringhe di comunicazione qui rimangono non tradotte (Installa, Rispondi) che dovrebbero essere affrontate in una traduzione più completa, ma anche una traduzione parziale sarebbe utile in molti casi.

Infine, dai un'occhiata all'eccellente risposta di F. Hauri.


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

Linux
  1. Come aggiungere i dati al buffer nello script della shell?

  2. Ottieni lo script da eseguire di nuovo se l'input è Sì?

  3. Formatta data e ora per lo script o la variabile della shell Linux

  4. Nascondere l'input dell'utente sul terminale nello script Linux

  5. Come cercare i file usando regex nello script della shell linux

Come eseguire il comando / script della shell di Linux in background

Script di shell per principianti - Come scrivere script Bash in Linux

Come memorizzare un comando Linux come variabile nello script della shell

Come eseguire lo script della shell come servizio SystemD in Linux

Linux:come eseguire uno script attivato da un input del joystick?

Come posso installare/creare un prompt personalizzato per i gusci di pesce?