Crie função genérica para fazer uma pergunta e verificar se a resposta está vazia

0

Estou criando um aplicativo de shell que faz muitas perguntas e estou usando read -p "<my_question>" <myvar> várias vezes. O problema é que eu também quero verificar se as respostas estão vazias. Então, imaginei criar uma função genérica para perguntar e verificar se está vazia ou não. Nesse caso, chame a função de forma recursiva, até que o usuário forneça algo. Quando eu 'fixo' o nome da variável como, digamos, 'userdatabase', as coisas funcionam maravilhosamente bem. Segue a declaração e uso da função:

ask() {
    read -p "$1" $2

    if [[ -z $userdatabase ]]; then
        echo Empty is not allowed
        ask "$1" $2
    else
        echo $userdatabase
    fi
}

ask "Provides the user database: " userdatabase

Claro, não quero colocar o "userdatabase" como nome de variável para todas as perguntas que o aplicativo fizer. Então, notei que preciso de um tipo de variável "dinâmica". Deixando as ideias um pouco mais dinâmicas, torna-se:

ask() {
    read -p "$1" $2

    if [[ -z $$var ]]; then
        echo Empty is not allowed
        ask "$1" $2
    else
        echo $$var
    fi
}

ask "Provides the user database: " $var

Mas quando eu uso o utilitário, recebo algo como SOMENUMBER. Obviamente, não estou usando a "variável dinâmica" no shell da maneira certa.

Então, como eu crio uma função que recebe a declaração da questão e um nome de variável que será preenchido com a variável do comando read -p ?

    
por danilocgsilva 07.03.2017 / 17:25

4 respostas

0

Eu gostaria de compartilhar algo que descobri tarde. Eu tentei adicionar mais uma etapa na validação da resposta: validar também se o caminho existe, e não consegui adaptar a solução Rakesh Sharma para isso. Finalmente, eu encontrei exatamente o que eu estava procurando, que é uma maneira de lidar com "variável dinâmica", e a maneira real de fazer isso é usando o $ {! Var}. Aqui está a versão final da minha função e seu uso:

ask_validate() {

    read -p "$1" $2

    if [ -z ${!2} ]; then
        echo Empty answer is not allowed.
        ask_validate "$1" $2
        return
    fi

    if ! [ -d ${!2} ]; then
        echo You need to provides an existing path
        ask_validate "$1" $2
        return
    fi

    echo The var name is: $2
    echo The var value is: ${!2}
}

ask_validate "Please, provides the host path: " host_path
ask_validate "Please, provides the virtual host configuration path: " virtualhost_path

echo The host path is $host_path
echo The virtual host configuration path is $virtualhost_path
    
por 15.03.2017 / 11:16
0

Comece com o caso mais simples possível. Faça uma função:

f() { read -p "Type smthng: " $1 ; }

Chame a função, atribuindo a variável $ p para manter sua entrada, então mostre a entrada após a função sai:

f p ; echo $p

Ele avisa, eu digito "woof" e echo $p produz o mesmo:

Type smthng: woof
woof

Uma forma de verificar a variável é agrupar essa função em outra:

g() { unset $1 ; until f "$1" && eval [ \"\$"$1"\" ] ; do echo wrong ; done ; }

A parte complicada é que o OP deseja atribuir o nome da variável como um parâmetro de função, para o qual eu uso um " mal " eval para analisar. Passar variáveis nomes como parâmetros de função raramente é feito, (ou necessário), mas isso mostra um método para fazer isso.

Teste:

g p ; echo $p

Ele avisa, eu teco Enter , ele exibe uma mensagem de erro; então no segundo prompt, eu digite "foo":

Type smthng: 
wrong
Type smthng: foo
foo

Esta parte do código OP não funciona:

if [[ -z $$var ]]; then

A $$ é uma variável bash que retorna o PID atual:

 man bash | grep -A 28 "Special Parameters$"  | sed -n '1,3p;28,$p'
   Special Parameters
       The shell treats several parameters specially.  These  parameters  may  only
       be referenced; assignment to them is not allowed.
       $      Expands to the process ID of the shell.  In a () subshell, it expands
              to the process ID of the current shell, not the subshell.
    
por 07.03.2017 / 17:53
0
ask() {
   # $1 ---> message to user
   # $2 ---> "VARIABLE NAME" in which read will store response

   case ${2-} in
      '' | *[!a-zA-Z0-9_]* | [0-9]* )
          echo >&2 "Oops you've selected an invalid variable name: \'$2'"
          exit 1;;
   esac

   read -p "$1" "$2"

   eval "
      case \${$2:++} in
         '' )
               echo >&2 'Empty response not allowed.'
               ask '$1' '$2';;
         * )
            echo \"\${$2}\";;
      esac
   "
}

VarName=${1-'humpty_dumpty'}
ask "Provide the user database: " "$VarName"
    
por 09.03.2017 / 17:59
0

So, I wondered to create a generic function to ask and verify if it is empty or not.

Essa é provavelmente uma boa ideia.

If so, call the function itself recursively, until user provides something.

Isso ... não é uma boa ideia. Apenas use um loop.

Pode ser comum em linguagens de programação funcionais usar recursão no lugar de loops simples, mas o shell não é um, e provavelmente não é muito inteligente também, então acho improvável que ele possa otimizar as chamadas finais. Em vez disso, você terá maior uso de memória se a recursão for profunda. Pode não ser um problema aqui, já que você provavelmente não recebe muitas iterações, mas, em geral, é melhor usar a recursão somente se precisar, por exemplo, ao andar uma estrutura de dados em forma de árvore.

Além disso, em vez de passar o nome da variável como um argumento para a função, você poderia fazer a atribuição no programa principal:

ask() {
        read -p "$1: " a
        while [ -z "$a" ] ; do
                echo "Please give a value" >&2
                read -p "$1: " a
        done
        echo "$a"
}

var=$(ask "please enter some value")    
echo "you gave $var"

Claro, agora temos que redirecionar o lembrete para stderr, porque stdout é atribuído à variável. Isso é o que o read faz com o prompt também. Isso também funciona, digamos, em dash , o que parece não suportar a referência indireta ${!x} .

    
por 15.03.2017 / 11:46