Eu estou tentando usar uma variável que consiste em diferentes seqüências de caracteres separadas com um |
como um case
teste de instrução. Por exemplo:
string="\"foo\"|\"bar\""
read choice
case $choice in
$string)
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
Quero poder digitar foo
ou bar
executar a primeira parte da case
declaração. No entanto, ambos foo
e bar
me levar para o segundo:
$ foo.sh
foo
Bad choice!
$ foo.sh
bar
Bad choice!
Usar em "$string"
vez de $string
não faz diferença. Nem usa string="foo|bar"
.
Eu sei que posso fazer assim:
case $choice in
"foo"|"bar")
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
Posso pensar em várias soluções alternativas, mas gostaria de saber se é possível usar uma variável como uma case
condição no bash. É possível e, se sim, como?
bash
shell-script
case
terdon
fonte
fonte
eval
opção $ escapando, $ parens, asensisk, asterisk, ponto-e-vírgula e novas linhas. Feio, mas "funciona".read
me parou. na minha opinião, a validação de entrada do usuário, que é isso que parece ser, oscase
padrões não devem estar no topo da lista de avaliação e devem ser reduzidos ao*
padrão padrão, de modo que os únicos resultados que chegam lá sejam garantidos aceitáveis. Ainda assim, como o problema é de ordem de análise / expansão, uma segunda avaliação pode ser necessária.Respostas:
O manual do bash declara:
Nenhuma «expansão de nome de caminho»
Assim: um padrão NÃO é expandido com «expansão de nome de caminho».
Portanto: um padrão NÃO pode conter "|" dentro. Somente: dois padrões podem ser unidos ao "|".
Isso funciona:
Usando «Globbing estendido»
No entanto,
word
é compatível com opattern
uso de regras de "expansão de nome de caminho".E «Extended Globbing» aqui , aqui e aqui permite o uso de padrões alternados ("|").
Isso também funciona:
Conteúdo da string
O próximo script de teste mostra que o padrão que corresponde a todas as linhas que contêm um
foo
oubar
qualquer lugar é'*$(foo|bar)*'
ou as duas variáveis$s1=*foo*
e$s2=*bar*
Script de teste:
fonte
Você pode usar a
extglob
opção:fonte
@(foo|bar)
especial em comparação comfoo|bar
? Ambos são padrões válidos que funcionam da mesma maneira quando digitados literalmente.|
não faz parte do padrãofoo|bar
, faz parte da sintaxe dacase
instrução permitir vários padrões em uma cláusula.|
faz parte do padrão estendido, no entanto.Você precisa de duas variáveis
case
porque o|
canal ou é analisado antes que os padrões sejam expandidos.Os padrões de shell nas variáveis são tratados de maneira diferente quando citados ou não entre aspas:
fonte
Se você deseja uma solução alternativa compatível com traços, escreva:
Explicação: awk é usado para dividir "string" e testar cada parte separadamente. Se "choice" corresponder à parte atualmente testada p [i], o comando awk será encerrado com "exit" na linha 11. Para o teste, o "case" do shell é usado (dentro de uma chamada de 'sistema') , como solicitado por Terdon. Isso mantém a possibilidade de modificar a "string" de teste pretendida, por exemplo, para "foo * | bar", a fim de corresponder também a "foooo" ("padrão de pesquisa"), como permite o "case" do shell. Se preferir expressões regulares, você pode omitir a chamada "system" e usar "~" ou "match" do awk.
fonte