Asignación variable fuera de la declaración del caso

8

En muchos idiomas es posible asignar el resultado de una declaración de caso / cambio a una variable, en lugar de repetir la asignación de variable muchas veces dentro de la declaración de caso. ¿Es posible hacer algo así en el shell Bash?

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

(O, como un aparte, en cualquier otro caparazón?)

iconoclasta
fuente
Tienes (s extra . De lo contrario, está bien.
HalosGhost

Respuestas:

6

La variable=$(...)construcción tomará la salida estándar de cualquier comando que se encuentre $(...)y se la asignará variable. Por lo tanto, para que le variableasignen la forma que desee, los valores deben enviarse a la salida estándar. Esto se hace fácilmente con el echocomando:

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

Esto funcionará bashtan bien como todos los demás shells POSIX.

Los Parens izquierdos opcionales

De acuerdo con el estándar POSIX, los parentes izquierdos en una casedeclaración son opcionales y lo siguiente también funciona:

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

Como Gilles señala en los comentarios, no todos los shells aceptan ambas formas en combinación con $(...): para una tabla de compatibilidad impresionantemente detallada, vea "$ ()" sustitución de comando vs. incrustado ")" .

John1024
fuente
Una página que revisé (no recuerdo dónde estaba) enumeraba la apertura (como opcional. Pensé que podría ayudar a evitar que )se malinterprete como el cierre )de la $(...)expresión.
iconoclasta
@iconoclast Sí. La apertura (es opcional: el código funciona igual sin o sin ellos. Los dejé solo porque, para bien o para mal, eso es tradición. La parte clave de la solución propuesta es el uso de echo.
John1024
1
Los shells @iconoclast Older (pre-POSIX) no permitían una apertura (para los casepatrones, pero algunos shells sí lo requerían y requerían la apertura (cuando casese usa en una sustitución de comando. Las conchas modernas están bien de cualquier manera. Ver in-ulm.de/~mascheck/various/cmd-subst
Gilles 'SO- deja de ser malvado'
1
@Gilles Gracias por esa información. La profundidad de su conocimiento es, como siempre, impresionante.
John1024
2

color_code=$(…)asigna la salida del comando a la variable color_code, con nuevas líneas finales eliminadas. Entonces necesita producir algo de salida. El código que escribió intenta ejecutar 1como un comando.

Puedes usar este idioma. Tenga en cuenta que color_codeestará vacío si $COLORninguno de los valores es compatible.

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

Pero no es muy idiomático. El lenguaje shell está orientado a combinaciones simples de comandos simples. Esta gran sustitución de comando es incómoda. La sustitución del comando crea una subshell, que es más lenta que el método directo:

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

La principal diferencia semántica entre los dos enfoques es que $(…)crea una subshell, de modo que cualquier asignación, salida, redirección, etc. que se realice adentro no tiene efecto afuera.

Gilles 'SO- deja de ser malvado'
fuente