web-dev-qa-db-fra.com

Comment obtenir un fichier écho de bash différemment en fonction des entrées de l'utilisateur?

Je suis assez nouveau dans les scripts Shell, mais j'aimerais écrire un script de base dans lequel le fichier bash fera écho à une ligne de texte différente en fonction de la saisie de l'utilisateur. Par exemple, si le script demande à l'utilisateur "Êtes-vous là?" et l'entrée de l'utilisateur est "oui" ou "oui", le script renvoie alors quelque chose comme "hello!". Mais si l'entrée de l'utilisateur est "non" ou "non", le script fera écho à autre chose. Et enfin, si la saisie de l'utilisateur est autre que oui/oui ou non/non, le script renvoie l'écho "répondez oui ou non". Voici ce que j'ai jusqu'à présent:

echo "Are you there?"  
read $input  

if [ $input == $yes ]; then  
    echo "Hello!"  
Elif [ $input == $no ]]; then  
    echo "Are you sure?"  
else  
    echo "Please answer yes or no."  
fi  

Cependant, peu importe l'entrée, je reçois toujours la première réponse ("Bonjour!")

De plus, j'aimerais incorporer du texte à la parole (comme je l'ai fait avec d'autres projets de fichiers bash utilisant festival). Dans d'autres fichiers bash, je l'ai fait de cette façon:

echo "Hello!"  
echo "Hello!" | festival --tts

Y a-t-il un moyen d'intégrer cela dans l'invite if then/yes no ci-dessus? Merci d'avance, j'utilise ceci pour créer des fichiers bash simples et m'aider à apprendre.

7
Santiago

Le problème principal est ici:

read $input

Dans bash, généralement, $foo est la valeur de la variable foo. Ici, vous ne voulez pas la valeur, mais le nom de la variable, donc ça devrait être juste:

read input

De même, dans les tests if, $yes et $no devraient être juste yes et no, puisque vous ne voulez que les chaînes yes et no.

Vous pouvez utiliser une instruction case ici, ce qui (IMHO) facilite la réalisation de plusieurs cas en fonction de l'entrée:

case $input in
[Yy]es)    # The first character can be Y or y, so both Yes and yes work
    echo "Hello!"  
    echo "Hello!" | festival --tts
    ;;
[Nn]o)     # no or No
    echo "Are you sure?"
    echo "Are you sure?" | festival --tts
    ;;
*)         # Anything else
    echo "Please answer yes or no."
    echo "Please answer yes or no." | festival --tts
    ;;
esac

Vous pouvez encapsuler les deux instructions echo et l'utilisation de festival dans une fonction pour éviter de vous répéter:

textAndSpeech ()
{
    echo "$@"
    echo "$@" | festival --tts
}
case $input in
[Yy]es)    # The first character can be Y or y, so both Yes and yes work
    textAndSpeech "Hello!"  
    ;;
[Nn]o)     # no or No
    textAndSpeech "Are you sure?"
    ;;
*)         # Anything else
    textAndSpeech "Please answer yes or no."
    ;;
esac

Avec $input, bash remplace ceci par sa valeur, qui n'est rien au départ. La commande read est donc:

read 

Et read enregistre par défaut l’entrée dans la variable REPLY. Ainsi, vous pouvez, si vous le souhaitez, éliminer la variable input et utiliser $REPLY au lieu de $input.


Regardez également l'instruction select dans Bash.

13
Olorin

TL; DR : corrige les erreurs de syntaxe, vérifie que le test [ contient des variables non vides, et crée une fonction permettant de rediriger teeen festivalnom__.

En ce qui concerne l'impression sur l'écran et la sortie sur festivalname__, je voudrais personnellement envelopper le script dans une fonction et diriger le tout vers festivalname__, avec teeentre les deux (ce qui envoie du texte à la fois à l'écran et au tuyau).

Il y a cependant trois problèmes de syntaxe à résoudre:

  • read $input devrait être read input. La variable de déréférence de symbole $ dans les scripts de shell (c.-à-d., Elle sera remplacée par $input par ce que contient inputname__).
  • Vous n'avez déclaré aucune variable yeset noname__. Ce que vous devriez faire est une comparaison de chaînes: [ "$input" == "yes" ]
  • ]] supplémentaire dans Elifname__

Quant à savoir pourquoi vous obtenez Hello! tout le temps, c’est exactement à cause des deux premiers points. Avant read $input, la variable inputn'existait pas. Vous ne faites donc que read(c'est-à-dire que la variable inexistante $input est déréférencée dans une chaîne vide, ne laissant que la commande readname__. Ainsi, tout ce que vous tapez est stocké dans la variable REPLYqui correspond à ce que readutilise quand aucun nom de variable n'a été donné. Et comme la variable yesn'existe pas, elle est également remplacée par une chaîne vide. Ainsi, en réalité, [ $input == $yes ] est traité comme [ "" == "" ] qui est toujours vrai.

$ [ $nonexistent == $anothernonexistent  ] && echo "Success"
Success

Le script corrigé doit être comme suit:

#!/bin/bash
main(){
    read -p "Are you there?" input  

    if [ "$input" == "yes" ]; then  
        echo "Hello!"  
    Elif [ "$input" == "no" ]; then  
        echo "Are you sure?"  
    else  
        echo "Please answer yes or no."  
    fi 
}
main | tee /dev/tty | festival --tts

N'oubliez pas de citez les variables et lisez-le sur différence entre = et == dans la commande de test .

14

Une troisième approche serait d’affecter une variable commune à chaque cas et d’agir en fin de compte sur cette variable. Je ne sais pas à quel point cette approche est courante dans bash, mais dans d'autres langages de programmation, elle est assez standard.

Également shopt -s nocasematch en conjonction avec [[ pour la comparaison de chaînes sans distinction de casse.
Avec cela aussi, YES et NO sont considérés comme une entrée valide.

shopt
[[

#!/bin/bash

shopt -s nocasematch

read -p "Are you there?" input  

if [[ "$input" == "yes" ]]; then  
    msg="Hello!"  
Elif [[ "$input" == "no" ]]; then  
    msg="Are you sure?"  
else  
    msg="Please answer yes or no."  
fi 

echo $msg
echo $msg | festival --tts
2
AkselA