Variable assignment outside of case statement

In many languages it is possible to assign the result of a case/switch statement to a variable, rather than repeating the variable assignment many times within the case statement. Is it possible to do something like this in the Bash shell?

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

(Or, as an aside, in any other shells?)

Asked By: iconoclast

||

The variable=$(...) construct will take the standard output of whatever command is in $(...) and assign it to variable. Thus, to get variable assigned the way that you want, the values have to be sent to standard output. This is easily done with the echo command:

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

This will work on bash as well as all other POSIX shells.

The Optional Left Parens

According to the POSIX standard, the left parens in a case statement is optional and the following works as well:

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

As Gilles points out in the comments, not all shells accept both forms in combination with $(...): for an impressively detailed table of compatibility, see “$( )” command substitution vs. embedded “)”.

Answered By: John1024

color_code=$(…) assigns the output of the command to the variable color_code, with final newlines stripped off. So you need to produce some output. The code you wrote attempts to execute 1 as a command.

You can use this idiom. Note that color_code will be empty if $COLOR is none of the supported values.

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

But it isn’t very idiomatic. The shell language is geared towards simple combinations of simple commands. This big command substitution is awkward. The command substitution creates a subshell, which is slower than the straightforward method:

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

The main semantic difference between the two approaches is that $(…) creates a subshell, so that any assignment, exit, redirection, etc. that is performed inside has no effect outside.

Categories: Answers Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.