Lire une variable dans bash avec une valeur par défaut


192

J'ai besoin de lire une valeur du terminal dans un script bash. Je voudrais pouvoir fournir une valeur par défaut que l'utilisateur peut modifier.

# Please enter your name: Ricardo^

Dans ce script, l'invite est "Veuillez entrer votre nom:" la valeur par défaut est "Ricardo" et le curseur se trouverait après la valeur par défaut. Existe-t-il un moyen de faire cela dans un script bash?

Réponses:


280

vous pouvez utiliser l' expansion des paramètres, par exemple

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

L'inclusion de la valeur par défaut dans l'invite entre crochets est une convention assez courante


7
J'ai fini par faire quelque chose sur cette base. Lecture dans une variable temporaire input, puis utilisation name=${input:-$name}.
Ricardo Marimon

41
Cela ne répond pas vraiment à la question. La valeur par défaut doit être affichée dans l'invite.
Dr.Personne Person II

3
et que va name=${!input:-$name}faire?
Harry Lee

8
@ Dr.PersonPersonII - vous pouvez ajouter la valeur par défaut en faisant quelque chose comme ceci: read -p "Entrez le nom d'hôte distant [$ remote_host_default]:" remote_host remote_host = $ {remote_host: - $ remote_host_default}
Dobler

5
$1devient${1:-some_default_string}
ThorSummoner

162
read -e -p "Enter Your Name:" -i "Ricardo" NAME

echo $NAME

1
Très bonne réponse! Je veux juste mentionner que j'avais des problèmes avec ça, parce que je n'ai pas vu l'espace entre "Ricardo" et NAME, mais une fois que j'ai compris ça ... magique ! Je vous remercie!
Mr Mikkél

40
malheureusement -i n'est pas une option valide pour OSX 10.7
non défini

3
@BrianMortenson Vous pouvez mettre à niveau bash en utilisant homebrew: stackoverflow.com/questions/16416195/…
antonagestam

2
Cette réponse montre comment faire fonctionner cela sur OS X (Bash 3.x): stackoverflow.com/questions/22634065/…
Christoph Petschnig

3
Notez simplement que cela -esemble être obligatoire pour permettre -ide travailler réellement
MestreLion

49

Dans Bash 4:

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

Cela affiche le nom après l'invite comme ceci:

Please enter your name: Ricardo

avec le curseur à la fin du nom et permet à l'utilisateur de le modifier. La dernière ligne est facultative et force le nom à être la valeur par défaut d'origine si l'utilisateur efface l'entrée ou la valeur par défaut (en soumettant une valeur nulle).


Impossible d'utiliser bash4 car il n'est pas standard dans les distributions Debian. J'ai besoin de quelque chose qui fonctionnera sans trop de tracas.
Ricardo Marimon

1
pas besoin de la dernière ligne de code, utilisez simplement à la nameplace de inputdans la readcommande.
RNA

2
@RNAer: En utilisant la variable supplémentaire, la valeur de $nameest conservée si l'utilisateur supprime la valeur proposée (et saisit donc une chaîne nulle). Tout dépend de vos besoins. Je l'ai dit dans ma réponse. Vous avez raison, cependant, que j'aurais pu être plus explicite et dire que si la ligne optionnelle n'avait pas été utilisée, la variable aurait pu l'être name.
Suspendu jusqu'à nouvel ordre.

1
@DennisWilliamson: Vous avez raison. C'est une bonne pratique si c'est ce que l'on veut.
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"

Exemple d'exécution:

Please enter IN_PATH [/tmp/input.txt]: 
Please enter OUT_PATH [/tmp/output.txt]: ~/out.txt
Input: /tmp/input.txt Output: ~/out.txt

J'aime cela car il suit la convention que je vois dans de nombreux scripts shell où la valeur par défaut est entre crochets avant les deux points. Merci!!!
morphatique

16

J'ai trouvé cette question en cherchant un moyen de présenter quelque chose comme:

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

En utilisant les exemples ci-dessus, j'ai déduit ceci: -

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

J'espère que cela aide quelqu'un à ne pas avoir à réfléchir à la logique, s'il rencontre le même problème


Très agréable. Il pourrait même être un peu amélioré de répéter la question si quelqu'un entre simplement "k" ou autre chose que les choix donnés.
erikbwork

1
Je viens d'écrire ce commentaire suite à une démangeaison rayée. J'ai maintenant une fonction shell, qui inclut ce qui précède, et j'ai tendance à l'utiliser. Shell ne semble pas bien boucler, alors j'essaye de l'éviter. Je pourrais tester le résultat de ma fonction et essayer encore une fois, mais en gros, j'écris des outils d'administration là où les choses pourraient mal tourner, donc je veux que l'administrateur puisse arrêter le script proprement à tout moment.
sibaz

11

Je viens d'utiliser ce modèle, que je préfère:

read name || name='(nobody)'

6
name=Ricardo
echo "Please enter your name: $name \c"
read newname
[ -n "$newname" ] && name=$newname

Définissez la valeur par défaut; imprime le; lire une nouvelle valeur; s'il y a une nouvelle valeur, utilisez-la à la place de la valeur par défaut. Il existe (ou existait) des variations entre les shells et les systèmes sur la façon de supprimer une nouvelle ligne à la fin d'une invite. La notation '\ c' semble fonctionner sur MacOS X 10.6.3 avec un bash 3.x, et fonctionne sur la plupart des variantes d'Unix dérivées de System V, en utilisant des shells Bourne ou Korn.

Notez également que l'utilisateur ne se rendrait probablement pas compte de ce qui se passe dans les coulisses; leurs nouvelles données seraient entrées après le nom déjà affiché à l'écran. Il vaut peut-être mieux le formater:

echo "Please enter your name ($name): \c"

printfest plus portable queecho
ghostdog74

3
@ ghostdog74: peut-être; ceux d'entre nous qui ont appris la programmation shell il y a plus de 25 ans ont du mal à déterminer lesquelles de nos pratiques sont encore pertinentes. Il semble de plus en plus que bash a réécrit à peu près tout. Je sais que printf existe depuis un certain temps en tant que commande - je l'utilise très rarement, cependant (probablement - jamais?). J'ai l'impression que je devrais me taire sur shell jusqu'à ce que j'aie (ré) appris bash. «C'est drôle; le logiciel sur lequel je travaille a des scripts shell qui ne fonctionnent pas bien - mais le problème n'est pas les bash-isms. J'en ai juste marre de la fixation ' if (test -z "$xxx"); ...' et d'autres shellismes C.
Jonathan Leffler

Je suis étonné que bash supporte \c, car il prend également en charge echo -n! Cependant, vous devez ajouter -epour obtenir l'écho de bash pour interpréter les échappements. Je suppose que \cc'est pour les choses non echo -e "Syntax slightly off\c, but I've learned so much from what you've shared. Thanks, @JonathanLeffler!"
dites

@Jonathan Leffler Malheureusement, pas vraiment ce que l'OP a demandé, du moins pas sur ma version bash 4.x $ bash --version GNU bash, version 4.3.33(0)-release a) "Je voudrais pouvoir fournir une valeur par défaut que l'utilisateur peut changer." Votre echo "Please enter your name: $name \c"ne me permet pas de modifier la valeur par défaut. b) "et le curseur serait après la valeur par défaut." Pas vrai non plus ... La réponse de @Paused jusqu'à nouvel ordre. répond aux deux exigences.
Bernie Reiter

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" }'

3
veuillez ajouter une explication à votre réponse.
Sufiyan Ghori

-1

Les paramètres -e et -t ne fonctionnent pas ensemble. J'ai essayé quelques expressions et le résultat était l'extrait de code suivant:

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

Votre réponse n'a pas grand-chose à voir avec la question, n'est-ce pas?…
gniourf_gniourf

c'est une solution pour utiliser les paramètres -e et -t. cette ligne de code (-e et -i pour la valeur par défaut): read -e -p "Entrez votre nom:" -i "Ricardo" NAME ne fonctionne pas avec un compte à rebours (-t)
speefak

Ouais mais ce n'est pas posé dans la question, n'est-ce pas?
gniourf_gniourf

3
Ce que vous pouvez faire, c'est poser une nouvelle question et y répondre vous-même ;). Ceci est autorisé sur SO! mais nous ne voulons pas polluer d'autres questions avec des choses sans rapport.
gniourf_gniourf
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.