Como obter o arquivo bash para fazer o eco de maneira diferente com base na entrada do usuário?

7

Sou bem novo em scripts de shell, mas gostaria de escrever um script básico em que o arquivo bash exibiria uma linha de texto diferente, dependendo da entrada do usuário. Por exemplo, se o script perguntar ao usuário "Você está aí?" e a entrada do usuário é "sim" ou "sim", então o script faria eco de "olá!". Mas se a entrada do usuário for "não" ou "não", o script fará eco a outra coisa. E, finalmente, se a entrada do usuário for algo diferente de sim / sim ou não / não, o script ecoará "Por favor responda sim ou não". Aqui está o que eu tenho até agora:

echo "Are you there?"  
read $input  

if [ $input == $yes ]; then  
    echo "Hello!"  
elif [ $input == $no ]]; then  
    echo "Are you sure?"  
else  
    echo "Please answer yes or no."  
fi  

No entanto, não importa a entrada, sempre recebo a primeira resposta ("Olá!")

Além disso, gostaria de incorporar o texto à fala (como fiz com outros projetos de arquivo bash usando festival). Em outros arquivos bash eu fiz assim:

echo "Hello!"  
echo "Hello!" | festival --tts

Existe uma maneira de incorporar isso no prompt if then / yes no acima? Agradeço antecipadamente, estou usando isso para criar arquivos simples do bash e ajudar-me a aprender.

    
por Santiago 20.05.2018 / 08:14

3 respostas

13

O principal problema está aqui:

read $input

No bash, geralmente, $foo é o valor da variável foo . Aqui, você não quer o valor, mas o nome da variável, por isso deve ser apenas:

read input

Da mesma forma, nos testes if , $yes e $no devem ser apenas yes e no , pois você deseja apenas as strings yes e no .

Você pode usar uma declaração case aqui, que (IMHO) facilita a realização de vários casos com base na entrada:

case $input in
[Yy]es)    # The first character can be Y or y, so both Yes and yes work
    echo "Hello!"  
    echo "Hello!" | festival --tts
    ;;
[Nn]o)     # no or No
    echo "Are you sure?"
    echo "Are you sure?" | festival --tts
    ;;
*)         # Anything else
    echo "Please answer yes or no."
    echo "Please answer yes or no." | festival --tts
    ;;
esac

Você pode agrupar as duas declarações echo e o uso de festival em uma função para evitar se repetir:

textAndSpeech ()
{
    echo "$@"
    echo "$@" | festival --tts
}
case $input in
[Yy]es)    # The first character can be Y or y, so both Yes and yes work
    textAndSpeech "Hello!"  
    ;;
[Nn]o)     # no or No
    textAndSpeech "Are you sure?"
    ;;
*)         # Anything else
    textAndSpeech "Please answer yes or no."
    ;;
esac

Com $input , o bash substitui isso pelo seu valor, que inicialmente não é nada, portanto, a execução do comando read é:

read 

E read por padrão armazena a entrada na variável REPLY . Então, se você quiser, elimine totalmente a variável input e use $REPLY em vez de $input .

Também dê uma olhada em a declaração select no Bash.

    
por Olorin 20.05.2018 / 08:35
14

TL; DR : corrija os erros de sintaxe, garanta que você tenha variáveis não vazias em [ test e faça uma função para percorrer tee em festival .

No que diz respeito à impressão para a tela e saída para festival , eu pessoalmente colocaria o script em uma função e canalizaria tudo para festival , com tee entre (que envia texto para a tela e para o pipe).

Existem três problemas de sintaxe a serem corrigidos:

  • read $input deve ser read input . A variável de referência de referência $ no script de shell (ou seja, $input será substituída pelo que input contém).
  • Você não tem yes e no variáveis declaradas. O que você deve fazer é a comparação de strings: [ "$input" == "yes" ]
  • Extra ]] em elif

Por que você recebe Hello! o tempo todo, é exatamente por causa dos dois primeiros pontos. Antes de read $input , a variável input não existe, portanto, você está executando apenas read (isto é, a variável inexistente $input é desreferenciada na sequência vazia, deixando apenas o comando read ). Portanto, o que você digitar será armazenado na variável REPLY , que é o que usa read quando nenhum nome de variável foi fornecido. E porque a variável yes não existe, ela também é substituída por string vazia. Portanto, na realidade, [ $input == $yes ] é tratado como [ "" == "" ] , o que é sempre verdadeiro.

$ [ $nonexistent == $anothernonexistent  ] && echo "Success"
Success

O script fixo deve ser assim:

#!/bin/bash
main(){
    read -p "Are you there?" input  

    if [ "$input" == "yes" ]; then  
        echo "Hello!"  
    elif [ "$input" == "no" ]; then  
        echo "Are you sure?"  
    else  
        echo "Please answer yes or no."  
    fi 
}
main | tee /dev/tty | festival --tts

Lembre-se de citar as variáveis e ler em diferença entre = e == no comando de teste .

    
por Sergiy Kolodyazhnyy 20.05.2018 / 08:56
2

Uma terceira abordagem seria atribuir a uma variável comum para cada caso e, no final, atuar sobre essa variável. Não tenho certeza de como essa abordagem é comum no bash, mas em outras linguagens de programação é bastante normal.

Também shopt -s nocasematch em conjunto com [[ para comparação de cadeias sem distinção entre maiúsculas e minúsculas.
Com isso, também YES e NO são tratados como entrada válida.

shopt
[[

#!/bin/bash

shopt -s nocasematch

read -p "Are you there?" input  

if [[ "$input" == "yes" ]]; then  
    msg="Hello!"  
elif [[ "$input" == "no" ]]; then  
    msg="Are you sure?"  
else  
    msg="Please answer yes or no."  
fi 

echo $msg
echo $msg | festival --tts
    
por AkselA 20.05.2018 / 23:46