Case dinamico [RESOLVIDO]

25. Re: Case dinamico [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 10/02/2017 - 18:02h

Não entendo realmente por que vocês estão insistindo com a construção em tempo de execução de um bloco usando case.

Na verdade, seria melhor voltar lá para o início, com o yutttttt explicando o que ele quer fazer, em vez de como. A não ser que ele esteja numa situação como a de ter de fazer um exercício usando case para uma questão de trabalho escolar que exija que seja feito de tal forma. Do contrário, parece-me artificiosamente mais complicado e ineficiente do que as alternativas mostradas acima, tanto por mim quanto por outros.


  


26. Re: Case dinamico [RESOLVIDO]

Marcelo Oliver
msoliver

(usa Debian)

Enviado em 10/02/2017 - 18:20h

yuttttttt escreveu:

msoliver escreveu:

yuttttttt escreveu:

msoliver escreveu:

Funcionou aqui . . .

#!/bin/bash
CASE=$(n=0;echo 'case $resposta in' ;for op in $(ls -1);do let n++; printf "%02d) ls -l %s ;;\n" $n $op ;done;echo -e "*) AJUDA ;;\nesac\n")
C="\x1B[0;38;5;156m"
F="\x1B[m"

INICIO() {
read -p " ESCOLHA UMA OPÇãO: " resposta
eval $(echo "$CASE")
}

AJUDA() {
echo -e "\n$C OPÇãO INVáLIDA$F\n"
}
INICIO


marcelo oliver


Cara assim deu certo, me explique esse %02d, o que é? e também se eu colocar %01d vai para uma casa, e se chegar em 10? como o bash tratará isso?

Justamente, o printf "%02d" 5
05
Imprime o nº com dois digitos . . .
Para ignorar o Nº de digitos, use o formato %s,
printf "%s" 5
5
SEpreferir, substitua o "printf" pelo "echo":
CASE=$(n=0;echo 'case $resposta in' ;for op in $(ls -1);do let n++; echo "$n) ls -l $op ;;\n";done;echo -e "*) AJUDA ;;\nesac\n") 

Precisando, estou por aqui . . .

Se a resposta foi satisfatória/esclarecedora, . . . MARQUE o tópico como resolvido, e, se gostou da minha "solução", Marque a minha resposta como a melhor . . . . Dessa forma sou pontuado, o que incentiva a continuar compartilhando o conhecimento . . .

Att.:
marcelo oliver.


Quando mudo para echo e digito 1 por exemplo, recebo esse erro:

./case-dinamico.sh: eval: line 14: erro de sintaxe proximo do `token' não eperado `2'


e preciso que seja echo para eu conseguir percorrer o array no for


Segue alteração com o "echo"
CASE=$(n=0;echo 'case $resposta in' ;for op in $(ls -1);do let n++; echo "$n) echo -e \" A OPÇãO ESCOLHIDA, é: $n\n\" ;;";done;echo -e "*) AJUDA ;;\nesac\n") 




27. Re: Case dinamico [RESOLVIDO]

yuttttttt
yuttttttt

(usa Outra)

Enviado em 10/02/2017 - 18:21h

paulo1205 escreveu:

Não entendo realmente por que vocês estão insistindo com a construção em tempo de execução de um bloco usando case.

Na verdade, seria melhor voltar lá para o início, com o yutttttt explicando o que ele quer fazer, em vez de como. A não ser que ele esteja numa situação como a de ter de fazer um exercício usando case para uma questão de trabalho escolar que exija que seja feito de tal forma. Do contrário, parece-me artificiosamente mais complicado e ineficiente do que as alternativas mostradas acima, tanto por mim quanto por outros.


Você não está entendo, não tem como eu utilizar o seu exemplo para a minha situação, não posso ficar acrescentando nomes manualmente toda hora que é mudado um diretório onde contem alguns arquivos que serão as opções, entende, a quantidade, nome, tipo de arquivo tudo isso poderá mudar, to criando o programa para se adaptar a essas mudanças, e não eu me adaptar a elas manualmente, seria cansativo. Prefiro cansar agora e criar todo o processo para tratar esse caso durante algumas horas, que ficar dias no trabalho braçal kkkkkkk Mas sim se não fosse por isso, eu também utilizaria um if, mas esse não é o caso. E agradeço a todos.




28. Re: Case dinamico

yuttttttt
yuttttttt

(usa Outra)

Enviado em 10/02/2017 - 18:43h

msoliver escreveu:

yuttttttt escreveu:

msoliver escreveu:

yuttttttt escreveu:

msoliver escreveu:

Funcionou aqui . . .

#!/bin/bash
CASE=$(n=0;echo 'case $resposta in' ;for op in $(ls -1);do let n++; printf "%02d) ls -l %s ;;\n" $n $op ;done;echo -e "*) AJUDA ;;\nesac\n")
C="\x1B[0;38;5;156m"
F="\x1B[m"

INICIO() {
read -p " ESCOLHA UMA OPÇãO: " resposta
eval $(echo "$CASE")
}

AJUDA() {
echo -e "\n$C OPÇãO INVáLIDA$F\n"
}
INICIO


marcelo oliver


Cara assim deu certo, me explique esse %02d, o que é? e também se eu colocar %01d vai para uma casa, e se chegar em 10? como o bash tratará isso?

Justamente, o printf "%02d" 5
05
Imprime o nº com dois digitos . . .
Para ignorar o Nº de digitos, use o formato %s,
printf "%s" 5
5
SEpreferir, substitua o "printf" pelo "echo":
CASE=$(n=0;echo 'case $resposta in' ;for op in $(ls -1);do let n++; echo "$n) ls -l $op ;;\n";done;echo -e "*) AJUDA ;;\nesac\n") 

Precisando, estou por aqui . . .

Se a resposta foi satisfatória/esclarecedora, . . . MARQUE o tópico como resolvido, e, se gostou da minha "solução", Marque a minha resposta como a melhor . . . . Dessa forma sou pontuado, o que incentiva a continuar compartilhando o conhecimento . . .

Att.:
marcelo oliver.


Quando mudo para echo e digito 1 por exemplo, recebo esse erro:

./case-dinamico.sh: eval: line 14: erro de sintaxe proximo do `token' não eperado `2'


e preciso que seja echo para eu conseguir percorrer o array no for


Segue alteração com o "echo"
CASE=$(n=0;echo 'case $resposta in' ;for op in $(ls -1);do let n++; echo "$n) echo -e \" A OPÇãO ESCOLHIDA, é: $n\n\" ;;";done;echo -e "*) AJUDA ;;\nesac\n") 



Consegui agora percorrer o array e deu tudo certo, valeu pela ajuda, tava morrendo de tanto procurar como fazer isso já kkkk só mais uma coisa, porque tenho que colocar \""\ antes da variável para funcionar? o que é isso? e o eval faz exatamente o que? dei uma pesquisada e li que eval tem que ser cuidadosamente utilizado para não causar problemas de segurança, que falhas de segurança poderiam ocorrer pelo uso do eval?


29. Re: Case dinamico [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 10/02/2017 - 18:56h

yuttttttt escreveu:

Você não está entendo, não tem como eu utilizar o seu exemplo para a minha situação, não posso ficar acrescentando nomes manualmente toda hora que é mudado um diretório onde contem alguns arquivos que serão as opções, entende, a quantidade, nome, tipo de arquivo tudo isso poderá mudar, to criando o programa para se adaptar a essas mudanças, e não eu me adaptar a elas manualmente, seria cansativo. Prefiro cansar agora e criar todo o processo para tratar esse caso durante algumas horas, que ficar dias no trabalho braçal kkkkkkk Mas sim se não fosse por isso, eu também utilizaria um if, mas esse não é o caso. E agradeço a todos.


Eu estou tentando entender o que você quer, mas em nenhum momento anterior você revelou isso. Só agora disse que queria alimentar suas opções com nomes de arquivos de um diretório.

Além do mais, os exemplos que eu coloquei foram apenas para mostrar as construções que você pode usar, não a forma final que seu programa deve ter. Minhas sugestões mencionam arrays comuns e arrays associativos, e mostram um jeito de preencher manualmente o array associativo, mas você poderia muito bem preenchê-los de modo automatizado, assim como automatizou a criação do bloco que vai submeter ao comando eval.


30. Re: Case dinamico [RESOLVIDO]

yuttttttt
yuttttttt

(usa Outra)

Enviado em 10/02/2017 - 19:21h

paulo1205 escreveu:

yuttttttt escreveu:

Você não está entendo, não tem como eu utilizar o seu exemplo para a minha situação, não posso ficar acrescentando nomes manualmente toda hora que é mudado um diretório onde contem alguns arquivos que serão as opções, entende, a quantidade, nome, tipo de arquivo tudo isso poderá mudar, to criando o programa para se adaptar a essas mudanças, e não eu me adaptar a elas manualmente, seria cansativo. Prefiro cansar agora e criar todo o processo para tratar esse caso durante algumas horas, que ficar dias no trabalho braçal kkkkkkk Mas sim se não fosse por isso, eu também utilizaria um if, mas esse não é o caso. E agradeço a todos.


Eu estou tentando entender o que você quer, mas em nenhum momento anterior você revelou isso. Só agora disse que queria alimentar suas opções com nomes de arquivos de um diretório.

Além do mais, os exemplos que eu coloquei foram apenas para mostrar as construções que você pode usar, não a forma final que seu programa deve ter. Minhas sugestões mencionam arrays comuns e arrays associativos, e mostram um jeito de preencher manualmente o array associativo, mas você poderia muito bem preenchê-los de modo automatizado, assim como automatizou a criação do bloco que vai submeter ao comando eval.


Mas teria que automatizar com eval do mesmo jeito, eu tentei utilizando condicionais antes do eval, e não consegui criar dinâmico como dá para fazer com o case. E não acho necessário dizer para que quero usar o case, o problema é que me deparei com uma situação que mesmo que eu ache outras soluções para ela iria querer saber como faço um case dinâmico, a questão é mais sobre a sintaxe do bash que da logica, logica não tem jeito, eu acredito, mesmo com a maioria sempre discordando, que cada um segue sua linha de raciocino e não deve e nem tem o porque padronizar isso, a não ser que você esteja preocupado com desempenho/segurança e precise fazer de certa maneira que já foi testada ser melhor, mas tudo é muito relativo de qualquer modo. Mas voltando kkkkk eu precisava saber como fazer um case dinâmico, porque caso um dia precise, já terei uma ideia de como fazer, sempre é bom aprender todas as formas possíveis, mesmo que não seja a melhor, para outra situação talvez ela possa ser.



31. Re: Case dinamico [RESOLVIDO]

yuttttttt
yuttttttt

(usa Outra)

Enviado em 10/02/2017 - 19:37h

msoliver escreveu:

yuttttttt escreveu:

msoliver escreveu:

yuttttttt escreveu:

msoliver escreveu:

yuttttttt escreveu:

msoliver escreveu:

Funcionou aqui . . .

#!/bin/bash
CASE=$(n=0;echo 'case $resposta in' ;for op in $(ls -1);do let n++; printf "%02d) ls -l %s ;;\n" $n $op ;done;echo -e "*) AJUDA ;;\nesac\n")
C="\x1B[0;38;5;156m"
F="\x1B[m"

INICIO() {
read -p " ESCOLHA UMA OPÇãO: " resposta
eval $(echo "$CASE")
}

AJUDA() {
echo -e "\n$C OPÇãO INVáLIDA$F\n"
}
INICIO


marcelo oliver


Cara assim deu certo, me explique esse %02d, o que é? e também se eu colocar %01d vai para uma casa, e se chegar em 10? como o bash tratará isso?

Justamente, o printf "%02d" 5
05
Imprime o nº com dois digitos . . .
Para ignorar o Nº de digitos, use o formato %s,
printf "%s" 5
5
SEpreferir, substitua o "printf" pelo "echo":
CASE=$(n=0;echo 'case $resposta in' ;for op in $(ls -1);do let n++; echo "$n) ls -l $op ;;\n";done;echo -e "*) AJUDA ;;\nesac\n") 

Precisando, estou por aqui . . .

Se a resposta foi satisfatória/esclarecedora, . . . MARQUE o tópico como resolvido, e, se gostou da minha "solução", Marque a minha resposta como a melhor . . . . Dessa forma sou pontuado, o que incentiva a continuar compartilhando o conhecimento . . .

Att.:
marcelo oliver.


Quando mudo para echo e digito 1 por exemplo, recebo esse erro:

./case-dinamico.sh: eval: line 14: erro de sintaxe proximo do `token' não eperado `2'


e preciso que seja echo para eu conseguir percorrer o array no for


Segue alteração com o "echo"
CASE=$(n=0;echo 'case $resposta in' ;for op in $(ls -1);do let n++; echo "$n) echo -e \" A OPÇãO ESCOLHIDA, é: $n\n\" ;;";done;echo -e "*) AJUDA ;;\nesac\n") 



Consegui agora percorrer o array e deu tudo certo, valeu pela ajuda, tava morrendo de tanto procurar como fazer isso já kkkk.
Só mais uma coisa,
01 porque tenho que colocar \""\ antes da variável para funcionar?
02 o que é isso?
03 e o eval faz exatamente o que?
dei uma pesquisada e li que eval tem que ser cuidadosamente utilizado para não causar problemas de segurança,
04 que falhas de segurança poderiam ocorrer pelo uso do eval?


Cara, era só mais "UMA" coisa, foram 04 . . . . . Rsrsrsrsrsr
01- uso o \$ é necessario, neste caso para que a VAR não seja resolvida nesse "echo", do mesmo modo, no 1º echo da var CASE usei aspa simples . . . .
02 - A "\" é usada para "escapar" o caracter, para que o mesmo seja interpretado literalmente
03 - Exemplo do eval:
echo "echo -e \" Se nao usar o eval, o 2º \"echo\" não é EXECUTADO\n MULTIPLICAÇãO:\n 5 x 5 = \$((5*5))\"" 

echo -e " Se nao usar o eval, o 2º "echo" não é EXECUTADO\n MULTIPLICAÇãO:\n 5 x 5 = $((5*5))"

eval $(echo "echo -e \" Se nao usar o eval, o 2º \"echo\" não é EXECUTADO\n MULTIPLICAÇãO:\n 5 x 5 = \$((5*5))\"") 

Se nao usar o eval, o 2º echo não é EXECUTADO
MULTIPLICAÇãO:
5 x 5 = 25



4 - Qquer comando utilizado erroneamente, pode causar danos . . .

Só uma "coisinha" . . . .
Marque a resposta como a melhor....


marcelo oliver




Pode deixar, vou fechar aqui agora, agradeço a ajuda de todos, e principalmente a sua, e quanto a segurança, dei uma pesquisada, vou deixar um link aqui para quem tiver interesse de saber um pouco o porque:

http://mywiki.wooledge.org/BashFAQ/048


32. Re: Case dinamico [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 10/02/2017 - 20:01h

yuttttttt escreveu:

Mas teria que automatizar com eval do mesmo jeito, eu tentei utilizando condicionais antes do eval, e não consegui criar dinâmico como dá para fazer com o case. E não acho necessário dizer para que quero usar o case, o problema é que me deparei com uma situação que mesmo que eu ache outras soluções para ela iria querer saber como faço um case dinâmico, a questão é mais sobre a sintaxe do bash que da logica, logica não tem jeito, eu acredito, mesmo com a maioria sempre discordando, que cada um segue sua linha de raciocino e não deve e nem tem o porque padronizar isso, a não ser que você esteja preocupado com desempenho/segurança e precise fazer de certa maneira que já foi testada ser melhor, mas tudo é muito relativo de qualquer modo. Mas voltando kkkkk eu precisava saber como fazer um case dinâmico, porque caso um dia precise, já terei uma ideia de como fazer, sempre é bom aprender todas as formas possíveis, mesmo que não seja a melhor, para outra situação talvez ela possa ser.


Eu não estou dizendo para você não fazer com case. Só que, às vezes, ideias preconcebidas podem não ser as melhores soluções para determinados problemas.

A título de informação, minha participação no fórum do VoL costuma ser apenas em comunidades voltadas para programação. Além de gostar de ajudar iniciantes, acho legal pôr meus conhecimentos em prática, e assim não enferrujar; encontrar, uma vez ou outra, problemas pelos quais nunca passei antes e que me obrigam a estudar um pouco para refinar meus conhecimentos; e, sobretudo, gosto de ajudar as pessoas a não incorrer em vícios de programação que um dia foram meus próprios vícios.

No seu caso (sem trocadilho) específico, você optou por uma construção que, na maioria das linguagens de programação, incluindo o próprio shell, foi projetada para ter um conjunto limitado e fixo de casos de uso. Sua forma de contornar essa limitação de projeto foi elaborar um código que, quando é executado, constrói outro programa, e depois executa esse outro programa de dentro do primeiro programa.

É uma solução válida?

É.

É a melhor?

Depende. Pode ser que seja a única possível, e nesse caso será a necessariamente a melhor. Mas para saber se existem alternativas, só mesmo sabendo o que você quer fazer.

No exemplo mostrado pelo msoliver e adotado por você, todos os casos de uso executam o mesmo comando sobre argumentos diferentes. Num caso assim, bastaria guardar os argumentos num array, e chamar o comando uma única vez após se ter selecionado o argumento desejado. Veja o exemplo abaixo.

declare -a arquivos   # digo explicitamente que “arquivos” designa um array,
arquivos=($(ls -1))
if (( ${#arquivos[@]} > 0 )) then
read -p "Informe o índice do arquivo (0 a $((${#arquivos[@]}-1))): " selecao
if [[ -n "$selecao" ]] && (( selecao<${#arquivos[@]} )); then
ls -l ${arquivos[$selecao]}
else
echo "Resposta inválida." >&2
fi
else
echo "Nenhum arquivo disponível para seleção." >&2
fi


Os dados podem variar; o programa não muda. Isso é mais eficiente de executar, mais fácil de entender, e mais fácil de dar manutenção.

E se os comandos variarem de acordo com com a seleção feita, o exemplo do msoliver não funcionaria diretamente. Você teria de ter alguma outra fonte externa de informação sobre qual comando executar sobre qual argumento. Qualquer que seja tal fonte, o programa estático poderia ler dela, e gravar num outro array ou num array associativo, como eu sugeri.

De todo modo, você parece já ter resolvido o problema. Bom para você.


33. Re: Case dinamico [RESOLVIDO]

yuttttttt
yuttttttt

(usa Outra)

Enviado em 10/02/2017 - 21:45h

paulo1205 escreveu:

yuttttttt escreveu:

Mas teria que automatizar com eval do mesmo jeito, eu tentei utilizando condicionais antes do eval, e não consegui criar dinâmico como dá para fazer com o case. E não acho necessário dizer para que quero usar o case, o problema é que me deparei com uma situação que mesmo que eu ache outras soluções para ela iria querer saber como faço um case dinâmico, a questão é mais sobre a sintaxe do bash que da logica, logica não tem jeito, eu acredito, mesmo com a maioria sempre discordando, que cada um segue sua linha de raciocino e não deve e nem tem o porque padronizar isso, a não ser que você esteja preocupado com desempenho/segurança e precise fazer de certa maneira que já foi testada ser melhor, mas tudo é muito relativo de qualquer modo. Mas voltando kkkkk eu precisava saber como fazer um case dinâmico, porque caso um dia precise, já terei uma ideia de como fazer, sempre é bom aprender todas as formas possíveis, mesmo que não seja a melhor, para outra situação talvez ela possa ser.


Eu não estou dizendo para você não fazer com case. Só que, às vezes, ideias preconcebidas podem não ser as melhores soluções para determinados problemas.

A título de informação, minha participação no fórum do VoL costuma ser apenas em comunidades voltadas para programação. Além de gostar de ajudar iniciantes, acho legal pôr meus conhecimentos em prática, e assim não enferrujar; encontrar, uma vez ou outra, problemas pelos quais nunca passei antes e que me obrigam a estudar um pouco para refinar meus conhecimentos; e, sobretudo, gosto de ajudar as pessoas a não incorrer em vícios de programação que um dia forão meus próprios vícios.

No seu caso (sem trocadilho) específico, você optou por uma construção que, na maioria das linguagens de programação, incluindo o próprio shell, foi projetada para ter um conjunto limitado e fixo de casos de uso. Sua forma de contornar essa limitação de projeto foi elaborar um código que, quando é executado, constrói outro programa, e depois executa esse outro programa de dentro do primeiro programa.

É uma solução válida?

É.

É a melhor?

Depende. Pode ser que seja a única possível, e nesse caso será a necessariamente a melhor. Mas para saber se existem alternativas, só mesmo sabendo o que você quer fazer.

No exemplo mostrado pelo msoliver e adotado por você, todos os casos de uso executam o mesmo comando sobre argumentos diferentes. Num caso assim, bastaria guardar os argumentos num array, e chamar o comando uma única vez após se ter selecionado o argumento desejado. Veja o exemplo abaixo.

declare -a arquivos   # digo explicitamente que “arquivos” designa um array,
arquivos=($(ls -1))
if (( ${#arquivos[@]} > 0 )) then
read -p "Informe o índice do arquivo (0 a $((${#arquivos[@]}-1))): " selecao
if [[ -n "$selecao" ]] && (( selecao<${#arquivos[@]} )); then
ls -l ${arquivos[$selecao]}
else
echo "Resposta inválida." >&2
fi
else
echo "Nenhum arquivo disponível para seleção." >&2
fi


Os dados podem variar; o programa não muda. Isso é mais eficiente de executar, mas fácil de entender, e mais fácil de dar manutenção.

E se os comandos variarem de acordo com com a seleção feita, o exemplo do msoliver não funcionaria diretamente. Você teria de ter alguma outra fonte externa de informação sobre qual comando executar sobre qual argumento. Qualquer que seja tal fonte, o programa estático poderia ler dela, e gravar num outro array ou num array associativo, como eu sugeri.

De todo modo, você parece já ter resolvido o problema. Bom para você.


Sim, não disse que você não ajuda, já me ajudou vária vezes aqui no forum, mas eu não consegui entender como fazer isso com if com seu exemplo, acredite eu tentei, ficou quase isso, mas eu estava comparando em vez de trabalhar o index do array como você fez. E sim o eval não seria adequado para esse caso, já que tem sim como fazer com o if, seria um risco desnecessário, alem da perca de desempenho para rodar um "sub-shell". Mas ainda assim é bom saber, agora sei das duas formas, e quero saber de outras, sempre mais, e assim conseguir criar outras, eu to programando em bash a poucos dias, nunca tinha mexido nisso, então não conheço muito a sintaxe dela, e fico limitado por isso as vezes, to tentando aprender, sempre lendo algo aqui ou ali para aprender e criar algo ao mesmo tempo, gosto de estudar assim. E sim vou usar o if é claro, mas como disse já foi bom saber sobre eval, me fez estudar o eval, agora sei porque não é seguro, sei o que é, quais maneiras não usar. E vou estudando assim kkkk

E uma coisa que aprendi errando e esqueci de falar aqui, no seu código você utiliza o ls, colocando ele dentro do array:

arquivos=($(ls -1)) 


Não é uma boa fazer isso, pode acontecer de você receber um array com seila 90 itens sendo que só tem 4 arquivos no diretório, especialmente se seus arquivos estejam nomeados com espaços ou com nomes extensos. É melhor substitui-lo por:

arquivos=($(pwd)/*.extensao) 


ou outros meios, como find, mas creio que o ls não seja o melhor para esses casos, já tive alguns problemas com ele em algumas situações.

Agradeço mais uma vez a ajuda de todos, aprendi muito com esse tópico, e creio que outros ao visitarem ele, também aprenderão.



01 02 03



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts