Designação de variável fora da instrução de caso

8

Em muitos idiomas, é possível atribuir o resultado de uma instrução case / switch a uma variável, em vez de repetir a atribuição da variável várias vezes na instrução case. É possível fazer algo assim no shell Bash?

color_code=$(case "$COLOR" in
  (red)    1;;
  (yellow) 2;;
  (green)  3;;
  (blue)   4;;
esac)

(Ou, como um aparte, em outras conchas?)

iconoclasta
fonte
Você tem (s extras . Caso contrário, está tudo bem.
HalosGhost

Respostas:

6

A variable=$(...)construção pegará a saída padrão de qualquer comando $(...)e a atribuirá variable. Portanto, para obter a variableatribuição desejada, os valores devem ser enviados para a saída padrão. Isso é feito facilmente com o echocomando:

color_code=$(case "$COLOR" in
  red)    echo 1;;
  yellow) echo 2;;
  green)  echo 3;;
  blue)   echo 4;;
esac)

Isso funcionará bash, assim como em todos os outros shells POSIX.

Parens opcionais à esquerda

De acordo com o padrão POSIX, a esquerda parens em uma caseinstrução é opcional e o seguinte também funciona:

color_code=$(case "$COLOR" in
  (red)    echo 1;;
  (yellow) echo 2;;
  (green)  echo 3;;
  (blue)   echo 4;;
esac)

Como Gilles aponta nos comentários, nem todos os shells aceitam os dois formulários em combinação com $(...): para uma tabela de compatibilidade impressionantemente detalhada, consulte "$ ()" substituição de comando vs. incorporado ")" .

John1024
fonte
Uma página que verifiquei (não me lembro onde estava) listou a abertura (como opcional. Eu pensei que poderia ajudar a evitar que o )erro seja interpretado como o fechamento )da $(...)expressão.
Iconoclast
@iconoclast Sim. A abertura (é opcional: o código funciona da mesma forma sem ou sem eles. Só os deixei de lado porque, para o bem ou para o mal, isso é tradição. A parte principal da solução proposta é o uso de echo.
John1024
1
As conchas mais antigas do @iconoclast (pré-POSIX) não permitiam uma abertura (para os casepadrões, mas algumas conchas exigiam a abertura (quando caseusadas em uma substituição de comando. Conchas modernas são boas de qualquer maneira. Veja in-ulm.de/~mascheck/various/cmd-subst
Gilles 'SO- stop
1
@ Gilles Obrigado por essa informação. A profundidade do seu conhecimento é, como sempre, impressionante.
John1024
2

color_code=$(…)atribui a saída do comando à variável color_code, com as novas linhas finais removidas. Então você precisa produzir alguma saída. O código que você escreveu tenta executar 1como um comando.

Você pode usar esse idioma. Observe que color_codeficará vazio se $COLORnenhum dos valores suportados.

color_code=$(case "$COLOR" in
  (red)    echo 1;;
  (yellow) echo 2;;
  (green)  echo 3;;
  (blue)   echo 4;;
esac)

Mas não é muito idiomático. A linguagem shell é voltada para combinações simples de comandos simples. Essa grande substituição de comando é estranha. A substituição do comando cria um subshell, que é mais lento que o método direto:

case "$COLOR" in
  red)    color_code=1;;
  yellow) color_code=2;;
  green)  color_code=3;;
  blue)   color_code=4;;
esac

A principal diferença semântica entre as duas abordagens é que $(…)cria um subshell, de forma que qualquer atribuição, saída, redirecionamento etc. executada por dentro não tem efeito externo.

Gilles 'SO- parar de ser mau'
fonte