Lesen Sie eine Variable in Bash mit einem Standardwert

191

Ich muss einen Wert vom Terminal in einem Bash-Skript lesen. Ich möchte in der Lage sein, einen Standardwert anzugeben, den der Benutzer ändern kann.

# Please enter your name: Ricardo^

In diesem Skript lautet die Eingabeaufforderung "Bitte geben Sie Ihren Namen ein:". Der Standardwert ist "Ricardo" und der Cursor befindet sich hinter dem Standardwert. Gibt es eine Möglichkeit, dies in einem Bash-Skript zu tun?

Ricardo Marimon
quelle

Antworten:

278

Sie können die Parametererweiterung verwenden, z

read -p "Enter your name [Richard]: " name
name=${name:-Richard}
echo $name

Das Einfügen des Standardwerts in die Eingabeaufforderung in Klammern ist eine weit verbreitete Konvention

Ghostdog74
quelle
7
Am Ende habe ich etwas getan, das darauf basiert. In eine temporäre Variable einlesen inputund dann verwenden name=${input:-$name}.
Ricardo Marimon
41
Dies beantwortet die Frage nicht wirklich. Der Standardwert sollte in der Eingabeaufforderung angezeigt werden.
Dr. Person Person II
3
und was wird name=${!input:-$name}tun?
Harry Lee
8
@ Dr.PersonPersonII - Sie können den Standardwert wie folgt hinzufügen: read -p "Geben Sie den Namen des Remote-Hosts ein [$ remote_host_default]:" remote_host remote_host = $ {remote_host: - $ remote_host_default}
Dobler
4
$1wird${1:-some_default_string}
ThorSummoner
159
read -e -p "Enter Your Name:" -i "Ricardo" NAME

echo $NAME
Jadav Bheda
quelle
1
Gute Antwort! Ich möchte nur erwähnen, dass ich Probleme damit hatte, weil ich den Raum zwischen "Ricardo" und NAME nicht gesehen habe, aber als ich das herausgefunden habe ... Magie ! Danke dir!
Herr Mikkél
40
Leider ist -i keine gültige Option für OSX 10.7
undefiniert
3
@BrianMortenson Sie können Bash mit Homebrew aktualisieren
antonagestam
2
Diese Antwort zeigt, wie dies unter OS X (Bash 3.x) funktioniert
Christoph Petschnig
3
Beachten Sie nur, dass -edies obligatorisch zu sein scheint, um -itatsächlich arbeiten zu können
MestreLion
48

In Bash 4:

name="Ricardo"
read -e -i "$name" -p "Please enter your name: " input
name="${input:-$name}"

Dies zeigt den Namen nach der Eingabeaufforderung wie folgt an:

Please enter your name: Ricardo

mit dem Cursor am Ende des Namens und ermöglicht dem Benutzer, ihn zu bearbeiten. Die letzte Zeile ist optional und erzwingt, dass der Name der ursprüngliche Standardwert ist, wenn der Benutzer die Eingabe oder den Standardwert löscht (Übermittlung einer Null).

Bis auf weiteres angehalten.
quelle
Bash4 kann nicht verwendet werden, da es in Debian-Distributionen nicht Standard ist. Ich brauche etwas, das ohne großen Aufwand funktioniert.
Ricardo Marimon
1
keine Notwendigkeit für die letzte Zeile des Codes, verwenden Sie einfach namestatt inputim readBefehl.
RNA
1
@RNAer: Durch Verwendung der zusätzlichen Variablen $namebleibt der Wert von erhalten, wenn der Benutzer den vorgeschlagenen Wert löscht (und somit eine Nullzeichenfolge eingibt). Es hängt alles davon ab, was Sie brauchen. Das habe ich in meiner Antwort gesagt. Sie haben jedoch Recht, dass ich expliziter hätte sein können und gesagt habe, dass die Variable hätte sein können, wenn die optionale Zeile nicht verwendet worden wäre name.
Bis auf weiteres angehalten.
1
@ TennisWilliamson: Du hast recht. Es ist eine gute Praxis, wenn man das will.
RNA
16

Code:

IN_PATH_DEFAULT="/tmp/input.txt"
read -p "Please enter IN_PATH [$IN_PATH_DEFAULT]: " IN_PATH
IN_PATH="${IN_PATH:-$IN_PATH_DEFAULT}"

OUT_PATH_DEFAULT="/tmp/output.txt"
read -p "Please enter OUT_PATH [$OUT_PATH_DEFAULT]: " OUT_PATH
OUT_PATH="${OUT_PATH:-$OUT_PATH_DEFAULT}"

echo "Input: $IN_PATH Output: $OUT_PATH"

Probelauf:

Please enter IN_PATH [/tmp/input.txt]: 
Please enter OUT_PATH [/tmp/output.txt]: ~/out.txt
Input: /tmp/input.txt Output: ~/out.txt
manish_s
quelle
Ich mag das, weil es der Konvention folgt, die ich in vielen Shell-Skripten sehe, bei denen der Standardwert in eckigen Klammern vor dem Doppelpunkt steht. Vielen Dank!!!
Morphatic
16

Ich fand diese Frage und suchte nach einer Möglichkeit, etwas zu präsentieren wie:

Something interesting happened.  Proceed [Y/n/q]:

Anhand der obigen Beispiele folgerte ich Folgendes: -

echo -n "Something interesting happened.  "
DEFAULT="y"
read -e -p "Proceed [Y/n/q]:" PROCEED
# adopt the default, if 'enter' given
PROCEED="${PROCEED:-${DEFAULT}}"
# change to lower case to simplify following if
PROCEED="${PROCEED,,}"
# condition for specific letter
if [ "${PROCEED}" == "q" ] ; then
  echo "Quitting"
  exit
# condition for non specific letter (ie anything other than q/y)
# if you want to have the active 'y' code in the last section
elif [ "${PROCEED}" != "y" ] ; then
  echo "Not Proceeding"
else
  echo "Proceeding"
  # do proceeding code in here
fi

Ich hoffe, das hilft jemandem, nicht über die Logik nachdenken zu müssen, wenn er auf dasselbe Problem stößt

sibaz
quelle
Sehr schön. Es könnte sogar ein wenig verbessert werden, die Frage zu wiederholen, wenn jemand nur "k" oder etwas anderes als die angegebenen Auswahlmöglichkeiten eingibt.
Erikbwork
1
Ich habe diesen Kommentar gerade nach einem zerkratzten Juckreiz geschrieben. Ich habe jetzt eine Shell-Funktion, die die oben genannten enthält, und ich neige dazu, diese zu verwenden. Shell scheint nicht gut zu schleifen, also versuche ich es zu vermeiden. Ich könnte das Ergebnis meiner Funktion testen und es noch einmal versuchen, aber im Grunde schreibe ich Admin-Tools, bei denen möglicherweise Probleme auftreten. Daher möchte ich, dass der Admin das Skript jederzeit sauber stoppen kann.
Sibaz
11

Ich habe gerade dieses Muster verwendet, das ich bevorzuge:

read name || name='(nobody)'
Bukzor
quelle
6
name=Ricardo
echo "Please enter your name: $name \c"
read newname
[ -n "$newname" ] && name=$newname

Legen Sie die Standardeinstellung fest. Druck es; einen neuen Wert lesen; Wenn es einen neuen Wert gibt, verwenden Sie ihn anstelle des Standardwerts. Es gibt (oder gab) einige Unterschiede zwischen Shells und Systemen, wie eine neue Zeile am Ende einer Eingabeaufforderung unterdrückt werden kann. Die '\ c'-Notation scheint unter MacOS X 10.6.3 mit einem 3.x-Bash zu funktionieren und funktioniert mit den meisten von System V abgeleiteten Unix-Varianten unter Verwendung von Bourne- oder Korn-Shells.

Beachten Sie auch, dass der Benutzer wahrscheinlich nicht erkennen würde, was sich hinter den Kulissen abspielt. Ihre neuen Daten werden nach dem Namen eingegeben, der bereits auf dem Bildschirm angezeigt wird. Es könnte besser sein, es zu formatieren:

echo "Please enter your name ($name): \c"
Jonathan Leffler
quelle
printfist tragbarer alsecho
ghostdog74
3
@ Ghostdog74: vielleicht so; Diejenigen von uns, die vor über 25 Jahren Shell-Programmierung gelernt haben, haben es schwer herauszufinden, welche unserer Praktiken noch relevant sind. Es sieht zunehmend so aus, als hätte bash so ziemlich alles neu geschrieben. Ich weiß, dass printf schon eine Weile als Befehl verwendet wurde - ich benutze es jedoch sehr selten (wahrscheinlich - nie?). Ich habe den Eindruck, ich sollte die Klappe halten, bis ich Bash (wieder) gelernt habe. Es ist lustig; Die Software, an der ich arbeite, enthält Shell-Skripte, die nicht gut funktionieren - aber das Problem sind keine Bash-Ismen. Ich habe es einfach satt, ' if (test -z "$xxx"); ...' und andere C-Shellismen zu reparieren.
Jonathan Leffler
Ich bin erstaunt, dass Bash unterstützt \c, da es auch unterstützt echo -n! Sie müssen jedoch hinzufügen -e, um das Bash-Echo für die Interpretation von Escape-Zeichen zu erhalten. Ich denke, \cist für Dinge, die nicht gesagt werden:echo -e "Syntax slightly off\c, but I've learned so much from what you've shared. Thanks, @JonathanLeffler!"
jpaugh
1
#Script for calculating various values in MB
echo "Please enter some input: "
read input_variable
echo $input_variable | awk '{ foo = $1 / 1024 / 1024 ; print foo "MB" }'
Kokane
quelle
3
Bitte fügen Sie Ihrer Antwort eine Erklärung hinzu.
Sufiyan Ghori
-1

Die Parameter -e und -t funktionieren nicht zusammen. Ich habe einige Ausdrücke ausprobiert und das Ergebnis war das folgende Code-Snippet:

QMESSAGE="SHOULD I DO YES OR NO"
YMESSAGE="I DO"
NMESSAGE="I DO NOT"
FMESSAGE="PLEASE ENTER Y or N"
COUNTDOWN=2
DEFAULTVALUE=n
#----------------------------------------------------------------#
function REQUEST ()
{
read -n1 -t$COUNTDOWN -p "$QMESSAGE ? Y/N " INPUT
    INPUT=${INPUT:-$DEFAULTVALUE}
    if  [ "$INPUT" = "y" -o "$INPUT" = "Y" ] ;then
        echo -e "\n$YMESSAGE\n"
        #COMMANDEXECUTION
    elif    [ "$INPUT" = "n" -o "$INPUT" = "N" ] ;then
        echo -e "\n$NMESSAGE\n"
        #COMMANDEXECUTION
    else
        echo -e "\n$FMESSAGE\n"
    REQUEST
    fi
}
REQUEST
speefak
quelle
Ihre Antwort hat nicht viel mit der Frage zu tun, oder?…
gniourf_gniourf
Es ist eine Problemumgehung für die Verwendung der Parameter -e und -t. Diese Codeline (-e und -i als Standardwert): read -e -p "Geben Sie Ihren Namen ein:" -i "Ricardo" NAME funktioniert nicht mit einem Countdowntimer (-t)
speefak
Ja, aber das wird in der Frage nicht gestellt, oder?
gniourf_gniourf
3
Sie können eine neue Frage stellen und diese selbst beantworten ;). Dies ist auf SO erlaubt! aber wir wollen andere Fragen nicht mit nicht verwandten Dingen verschmutzen.
gniourf_gniourf