Leia uma variável no bash com um valor padrão

191

Eu preciso ler um valor do terminal em um script bash. Eu gostaria de poder fornecer um valor padrão que o usuário possa alterar.

# Please enter your name: Ricardo^

Neste script, o prompt é "Por favor, digite seu nome:" o valor padrão é "Ricardo" e o cursor estará após o valor padrão. Existe uma maneira de fazer isso em um script bash?

Ricardo Marimon
fonte

Respostas:

278

você pode usar a expansão de parâmetros, por exemplo

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

Incluir o valor padrão no prompt entre parênteses é uma convenção bastante comum

ghostdog74
fonte
7
Acabei fazendo algo baseado nisso. Lendo uma variável temp inpute depois usando name=${input:-$name}.
Ricardo Marimon
41
Na verdade, isso não responde à pergunta. O valor padrão deve ser exibido no prompt.
Persona Pessoa II
3
e o que vai name=${!input:-$name}fazer?
Harry Lee
8
@ Dr.PersonPersonII - você pode adicionar o valor padrão fazendo algo assim: read -p "Digite o nome do host remoto [$ remote_host_default]:" remote_host remote_host = $ {remote_host: - $ remote_host_default}
Dobler
4
$1torna${1:-some_default_string}
24416 ThorSummoner
159
read -e -p "Enter Your Name:" -i "Ricardo" NAME

echo $NAME
Jadav Bheda
fonte
1
Ótima resposta! Só quero mencionar que estava tendo problemas com isso, porque não via o espaço entre "Ricardo" e NAME, mas uma vez descobri isso ... mágica ! Obrigado!
Mikkél
40
infelizmente -i não é uma opção válida para OSX 10.7
indefinido
3
@BrianMortenson Você pode atualizar o bash usando o homebrew: stackoverflow.com/questions/16416195/…
antonagestam
2
Esta resposta mostra como fazer isso funcionar no OS X (Bash 3.x): stackoverflow.com/questions/22634065/…
Christoph Petschnig
3
Observe que -eparece ser obrigatório permitir-i para realmente trabalho
MestreLion
48

No Bash 4:

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

Isso exibe o nome após o prompt da seguinte maneira:

Please enter your name: Ricardo

com o cursor no final do nome e permite ao usuário editá-lo. A última linha é opcional e força o nome a ser o padrão original se o usuário apagar a entrada ou o padrão (enviando um nulo).

Pausado até novo aviso.
fonte
Não é possível usar o bash4 porque não é padrão nas distribuições debian. Eu preciso de algo que funcione sem muito aborrecimento.
Ricardo Marimon
1
não há necessidade da última linha de código, basta usar em namevez de inputno readcomando
RNA
1
@RNAer: Ao usar a variável extra, o valor de $nameé preservado se o usuário excluir o valor proposto (e, assim, inserir uma string nula). Tudo depende de qual é a sua necessidade. Eu disse isso na minha resposta. Você está certo, porém, que eu poderia ter sido mais explícito e disse que se a linha opcional não fosse usada, a variável poderia ter sido name.
Pausado até novo aviso.
1
@DennisWilliamson: Você está certo. É uma boa prática se é isso que se quer.
RNA
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"

Exemplo de execução:

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
fonte
Eu gosto disso porque segue a convenção que vejo em muitos scripts de shell em que o valor padrão está entre colchetes antes dos dois pontos. Obrigado!!!
morphatic
16

Encontrei esta pergunta, procurando uma maneira de apresentar algo como:

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

Usando os exemplos acima, deduzi o seguinte:

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 ajude alguém a não ter que pensar na lógica, se encontrar o mesmo problema

sibaz
fonte
Muito agradável. Pode até ser um pouco melhor repetir a pergunta se alguém digitar "k" ou algo mais do que as opções dadas.
precisa saber é o seguinte
1
Acabei de escrever este comentário após uma coceira riscada. Agora eu tenho uma função shell, que inclui o acima, e eu costumo usá-la. A Shell não parece funcionar muito bem, então tento evitá-la. Posso testar o resultado da minha função e tentar mais uma vez, mas, basicamente, estou escrevendo ferramentas administrativas onde as coisas podem dar errado, por isso quero que o administrador possa interromper o script corretamente a qualquer momento.
Sibaz 11/04
11

Acabei de usar esse padrão, o qual prefiro:

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

Defina o padrão; imprima; leia um novo valor; se houver um novo valor, use-o no lugar do padrão. Há (ou houve) algumas variações entre shells e sistemas sobre como suprimir uma nova linha no final de um prompt. A notação '\ c' parece funcionar no MacOS X 10.6.3 com um bash 3.x e funciona na maioria das variantes do Unix derivadas do System V, usando shells Bourne ou Korn.

Observe também que o usuário provavelmente não perceberia o que está acontecendo nos bastidores; seus novos dados seriam inseridos após o nome já na tela. Talvez seja melhor formatá-lo:

echo "Please enter your name ($name): \c"
Jonathan Leffler
fonte
printfé mais portátil queecho
ghostdog74
3
@ ghostdog74: talvez sim; aqueles de nós que aprenderam a programação de shell há mais de 25 anos têm dificuldade em descobrir quais de nossas práticas ainda são relevantes. Parece cada vez mais que o bash reescreveu quase tudo. Sei que printf já existe há algum tempo como um comando - embora raramente o use (provavelmente - nunca?). Tenho a impressão de que devo calar a boca até que (re) aprendi o bash. É engraçado; o software em que trabalho possui shell scripts que não funcionam bem - mas o problema não é o bash-isms. Eu apenas me if (test -z "$xxx"); ...canso de consertar ' ' e outros shellismos em C.
Jonathan Leffler
Estou surpreso que o bash suporta \c, pois também suporta echo -n! No entanto, você precisa adicionar -epara obter o eco do bash para interpretar escapes. Eu acho que \cé para coisas ditas: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
fonte
3
adicione explicação à sua resposta.
Sufiyan Ghori
-1

Os parâmetros -e e -t não funcionam juntos. Eu tentei algumas expressões e o resultado foi o seguinte trecho 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
fonte
A sua resposta não tem muito a ver com a questão, tem-no ...?
gniourf_gniourf
é uma solução alternativa para o uso dos parâmetros -e e -t. este codeline (-e e -i para o valor padrão): ler -e -p "Digite seu nome:" -i "Ricardo" NAME não funciona com um CountdownTimer (-t)
speefak
Sim, mas isso não é perguntado na pergunta, é?
gniourf_gniourf
3
O que você pode fazer é fazer uma nova pergunta e responder você mesmo ;). Isso é permitido no SO! mas não queremos poluir outras perguntas com coisas não relacionadas.
gniourf_gniourf