Leer una variable en bash con un valor predeterminado


192

Necesito leer un valor desde la terminal en un script bash. Me gustaría poder proporcionar un valor predeterminado que el usuario pueda cambiar.

# Please enter your name: Ricardo^

En este script, el mensaje es "Por favor ingrese su nombre:" el valor predeterminado es "Ricardo" y el cursor estará después del valor predeterminado. ¿Hay alguna manera de hacer esto en un script bash?

Respuestas:


280

puede usar la expansión de parámetros, por ejemplo

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

Incluir el valor predeterminado en la solicitud entre paréntesis es una convención bastante común


77
Terminé haciendo algo basado en esto. Lectura en una variable temporal inputy luego usando name=${input:-$name}.
Ricardo Marimon

41
Esto en realidad no responde la pregunta. El valor predeterminado debe mostrarse en la solicitud.
Dr. Person Person II

3
y lo que va a name=${!input:-$name}hacer?
Harry Lee

8
@ Dr.PersonPersonII: puede agregar el valor predeterminado haciendo algo como esto: leer -p "Ingrese el nombre de host remoto [$ remote_host_default]:" remote_host remote_host = $ {remote_host: - $ remote_host_default}
Dobler

55
$1se convierte en${1:-some_default_string}
ThorSummoner

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

echo $NAME

1
¡Gran respuesta! Solo quiero mencionar que estaba teniendo problemas con eso, porque no vi el espacio entre "Ricardo" y NAME, pero una vez que lo descubrí ... ¡ magia ! ¡Gracias!
Sr. Mikkél

40
desafortunadamente -i no es una opción válida para OSX 10.7
indefinido el

3
@BrianMortenson Puede actualizar bash usando homebrew: stackoverflow.com/questions/16416195/…
antonagestam

2
Esta respuesta muestra cómo hacer que esto funcione en OS X (Bash 3.x): stackoverflow.com/questions/22634065/…
Christoph Petschnig

3
Solo tenga en cuenta que -eparece ser obligatorio permitir -ique realmente funcione
MestreLion

49

En Bash 4:

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

Esto muestra el nombre después del mensaje de esta manera:

Please enter your name: Ricardo

con el cursor al final del nombre y permite al usuario editarlo. La última línea es opcional y obliga al nombre a ser el predeterminado original si el usuario borra la entrada o el predeterminado (enviando un valor nulo).


No se puede usar bash4 porque no es estándar en las distribuciones de Debian. Necesito algo que funcione sin mucha molestia.
Ricardo Marimon

1
no necesita la última línea de código, solo use en namelugar de inputen el readcomando.
ARN

2
@RNAer: Al usar la variable adicional, el valor de $namese conserva si el usuario elimina el valor propuesto (y por lo tanto ingresa una cadena nula). Todo depende de cuál sea su necesidad. Lo dije en mi respuesta. Sin embargo, tiene razón, podría haber sido más explícito y decir que si no se usara la línea opcional, entonces la variable podría haber sido name.
Pausado hasta nuevo aviso.

1
@DennisWilliamson: Tienes razón. Es una buena práctica si eso es lo que uno quiere.
ARN

16

Código:

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"

Ejecución de muestra:

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

Me gusta esto porque sigue la convención que veo en muchos scripts de shell donde el valor predeterminado está entre corchetes antes de los dos puntos. ¡¡¡Gracias!!!
morpático

16

Encontré esta pregunta, buscando una forma de presentar algo como:

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

Usando los ejemplos anteriores deduje esto: -

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

Espero que ayude a alguien a no tener que pensar la lógica, si encuentran el mismo problema


Muy agradable. Incluso podría mejorarse un poco repetir la pregunta si alguien ingresa "k" o algo más que las opciones dadas.
erikbwork

1
Acabo de escribir este comentario después de una picazón rayada. Ahora tengo una función de shell, que incluye lo anterior, y tiendo a usarla. Shell no parece estar bien, así que trato de evitarlo. Podría probar el resultado de mi función y darle una oportunidad más, pero básicamente, estoy escribiendo herramientas de administración donde las cosas pueden salir mal, así que quiero que el administrador pueda detener el script limpiamente en cualquier momento.
sibaz

11

Acabo de usar este patrón, que prefiero:

read name || name='(nobody)'

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

Establecer el valor predeterminado; Imprímelo; leer un nuevo valor; Si hay un nuevo valor, úselo en lugar del predeterminado. Hay (o hubo) algunas variaciones entre shells y sistemas sobre cómo suprimir una nueva línea al final de un aviso. La notación '\ c' parece funcionar en MacOS X 10.6.3 con un bash 3.x, y funciona en la mayoría de las variantes de Unix derivadas del Sistema V, usando shells Bourne o Korn.

También tenga en cuenta que el usuario probablemente no se dará cuenta de lo que está sucediendo detrás de escena; sus nuevos datos se ingresarían después del nombre que ya está en la pantalla. Puede ser mejor formatearlo:

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

printfes más portátil queecho
ghostdog74

3
@ ghostdog74: tal vez sí; aquellos de nosotros que aprendimos la programación de shell hace más de 25 años, nos resulta difícil determinar cuáles de nuestras prácticas siguen siendo relevantes. Cada vez más parece que bash ha reescrito casi todo. Sé que printf ha existido desde hace un tiempo como un comando, aunque rara vez lo uso (probablemente, ¿nunca?). Tengo la impresión de que debería callarme en Shell hasta que haya (re) aprendido bash. Es gracioso; el software en el que trabajo tiene scripts de shell que no funcionan bien, pero el problema no es bash-isms. Simplemente estoy harto de arreglarlo ' if (test -z "$xxx"); ...' y de otros shellismos en C.
Jonathan Leffler

¡Estoy sorprendido de que bash sea compatible \c, ya que también es compatible echo -n! Sin embargo, debe agregar -epara obtener el eco de bash para interpretar escapes. Creo que \ces por las cosas que no se dijeron:echo -e "Syntax slightly off\c, but I've learned so much from what you've shared. Thanks, @JonathanLeffler!"
jpaugh

@ Jonathan Leffler Desafortunadamente, no es realmente lo que solicitó el OP, al menos no en mi versión bash 4.x $ bash --version GNU bash, version 4.3.33(0)-release a) "Me gustaría poder proporcionar un valor predeterminado que el usuario pueda cambiar". Tu echo "Please enter your name: $name \c"no me permite editar el valor predeterminado. b) "y el cursor estaría después del valor predeterminado". No es cierto, tampoco ... La respuesta de @Paused hasta nuevo aviso. cumple ambos requisitos.
Bernie Reiter hace

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
por favor agregue una explicación a su respuesta.
Sufiyan Ghori

-1

Los parámetros -e y -t no funcionan juntos. Probé algunas expresiones y el resultado fue el siguiente fragmento de código:

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

Su respuesta no tiene mucho que ver con la pregunta, ¿verdad? ...
gniourf_gniourf

es una solución para usar los parámetros -e y -t. esta línea de código (-e e -i para el valor predeterminado): lea -e -p "Ingrese su nombre:" -i "Ricardo" NAME no funciona con un temporizador de cuenta regresiva (-t)
speefak

Sí, pero eso no se hace en la pregunta, ¿verdad?
gniourf_gniourf

3
Lo que puede hacer es hacer una nueva pregunta y responderla usted mismo ;). Esto está permitido en SO! pero no queremos contaminar otras preguntas con cosas no relacionadas.
gniourf_gniourf
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.