Wie kann man eine Bash-Datei basierend auf Benutzereingaben unterschiedlich wiedergeben lassen?

7

Ich bin ziemlich neu in Shell-Skripten, aber ich möchte ein einfaches Skript schreiben, in dem die Bash-Datei je nach Benutzereingabe eine andere Textzeile wiedergibt. Zum Beispiel, wenn das Skript den Benutzer fragt "Sind Sie da?" und die Benutzereingabe ist "Ja" oder "Ja", dann würde das Skript so etwas wie "Hallo!" wiedergeben. Wenn die Benutzereingabe jedoch "Nein" oder "Nein" lautet, gibt das Skript etwas anderes wieder. Und schließlich, wenn die Benutzereingabe etwas anderes als Ja / Ja oder Nein / Nein ist, würde das Skript "Bitte antworten Sie mit Ja oder Nein" wiedergeben. Folgendes habe ich bisher:

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  

Unabhängig von der Eingabe erhalte ich jedoch immer die erste Antwort ("Hallo!")

Außerdem möchte ich Text in die Sprache integrieren (wie ich es bei anderen Bash-File-Projekten mit Festival getan habe). In anderen Bash-Dateien habe ich es so gemacht:

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

Gibt es eine Möglichkeit, dies in die obige Eingabeaufforderung if then / yes no aufzunehmen? Vielen Dank im Voraus, ich verwende dies, um einfache Bash-Dateien zu erstellen und mir selbst beim Lernen zu helfen.

Santiago
quelle
1
Verwenden Sie Shellcheck , um Shell-Skripte zu debuggen (auch im gleichnamigen Paket verfügbar ). Es wird eine Notiz zu den bestimmten Problemen in Ihrem Skript gedruckt.
David Foerster
Es ist auch eine gute Idee, ein Skript mit set -xoben auszuführen , um die Diagnoseausgabe anzuzeigen.
Sergiy Kolodyazhnyy

Antworten:

13

Das Hauptproblem ist hier:

read $input

In bash ist normalerweise $fooder Wert der Variablen foo. Hier möchten Sie nicht den Wert, sondern den Namen der Variablen, also sollte es nur sein:

read input

Ebenso in den ifTests, $yesund $nosollte gerecht yesund sein no, da Sie nur die Zeichenfolgen yesund nodort wollen.

Sie können casehier eine Anweisung verwenden, die es (IMHO) einfacher macht, mehrere Fälle basierend auf Eingaben durchzuführen:

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

Sie können die beiden echoAnweisungen und die Verwendung von festivalin eine Funktion einschließen, um zu vermeiden, dass Sie sich wiederholen:

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

Mit $inputersetzt bash dies durch seinen Wert, der anfangs nichts ist. Der readBefehlslauf lautet also:

read 

Und readstandardmäßig speichert die Eingabe in den Variablen REPLY. Wenn Sie möchten, können Sie die inputVariable also vollständig entfernen und $REPLYstattdessen verwenden $input.


Schauen Sie sich auch die selectAussage in Bash an.

Olorin
quelle
Ich danke dir sehr! Ich habe überall nach dieser einfachen Lösung gesucht, konnte sie aber nicht finden. Meine einzige andere Frage ist, wie ich es zu einer Schleife machen würde. Lassen Sie das Skript beispielsweise so lange eine Schleife durchlaufen, bis der Benutzer mit "Ja" antwortet, anstatt nur nach der angegebenen Antwort zu enden. Ich danke dir sehr!
Santiago
@ Santiago machen es eine while true; do...doneSchleife, mit breakAnweisung direkt danach echo "Hello!".
Sergiy Kolodyazhnyy
@ Santiago das ist genau das, wofür die selectAussage ist! In einer selectAnweisung wird der Benutzer wiederholt aufgefordert, eine der verfügbaren Optionen auszuwählen. Basierend auf diesen Optionen können Sie dann entscheiden, ob Sie breakdie selectAnweisung verlassen oder die Schleife fortsetzen möchten. Siehe Beispiel: paste.ubuntu.com/p/Ztp3XGCKtF
Olorin
14

TL; DR : fix Syntaxfehler, sicherzustellen , dass Sie tatsächlich nicht leere Variablen in haben [Test, und eine Funktion zum Rohr durchstehen teezu festival.

Soweit zum Siebdrucken und zur Ausgabe an festival, ich persönlich würde das Skript in eine Funktion und Rohr alles wickelt festival, mit teedazwischen (welchem Text sowohl auf Bildschirm und Rohr sendet).

Es müssen jedoch drei Syntaxprobleme behoben werden:

  • read $inputsollte sein read input. Die $Symbol-Dereferenzierungsvariable in Shell-Skripten (dh sie $inputwird durch das ersetzt, was inputgilt).
  • Sie haben keine yesund noVariablen deklariert. Was Sie tun sollten, ist ein Zeichenfolgenvergleich:[ "$input" == "yes" ]
  • Extra ]]inelif

Warum Sie die Hello!ganze Zeit bekommen, liegt genau an den ersten beiden Aufzählungspunkten. Bevor read $inputdie Variable inputnicht existiert, führen Sie nur eine Leistung aus read(dh eine nicht vorhandene Variable $inputwird in eine leere Zeichenfolge dereferenziert, wobei nur der readBefehl dort verbleibt ). Was auch immer Sie eingeben, wird in der REPLYVariablen gespeichert , die readverwendet wird, wenn kein Variablenname angegeben wurde. Und weil yeskeine Variable existiert, wird diese auch durch eine leere Zeichenfolge ersetzt. So wird in Wirklichkeit [ $input == $yes ]so behandelt, wie [ "" == "" ]es immer wahr ist.

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

Das feste Skript sollte wie folgt aussehen:

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

Denken Sie daran, die Variablen in Anführungszeichen zu setzen und sich über den Unterschied zwischen =und ==im Testbefehl zu informieren .

Sergiy Kolodyazhnyy
quelle
Kann Tee verwendet werden, um cmatrix ins Festival zu leiten? .. fragen Sie einfach nicht, wofür.
Willtech
@ Willtech Nun ja, das kann es. Alle Zeichenanzeigen cmatrixscheinen aus dem tragbaren Zeichensatz zu stammen, daher sehe ich kein Problem mit anderen Gebietsschema-Zeichen wie im "echten" Matrixfluss. Aber ich bin mir nicht sicher, wie festivaldas funktionieren würde, es wäre nur eine Menge Kauderwelsch. Aber theoretisch würde es gut funktionieren.
Sergiy Kolodyazhnyy
2

Ein dritter Ansatz wäre, für jeden Fall eine gemeinsame Variable zuzuweisen und letztendlich auf diese Variable einzuwirken. Ich bin mir nicht sicher, wie häufig dieser Ansatz in Bash ist, aber in anderen Programmiersprachen ist er ziemlich Standard.

Auch shopt -s nocasematchin Verbindung mit [[zum Vergleich von Zeichenfolgen ohne Berücksichtigung der Groß- und Kleinschreibung.
Damit auch YESund NOwerden als gültige Eingabe getreten.

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
AkselA
quelle