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?

Ricardo Marimon
fuente

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

ghostdog74
fuente
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
Jadav Bheda
fuente
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).

Pausado hasta nuevo aviso.
fuente
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
manish_s
fuente
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

sibaz
fuente
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)'
bukzor
fuente
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"
Jonathan Leffler
fuente
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" }'
kokane
fuente
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
speefak
fuente
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