Case statement fallthrough?

Bash

Bash Problem Overview


In popular imperative languages, switch statements generally "fall through" to the next level once a case statement has been matched.

Example:

int a = 2;
switch(a)
{
   case 1:
      print "quick ";
   case 2: 
      print "brown ";
   case 3: 
      print "fox ";
      break;
   case 4:
      print "jumped ";
}

would print "brown fox".

However the same code in bash

A=2
case $A in
2)
  echo "QUICK"
  ;&
2)
  echo "BROWN"
  ;&
3)
  echo "FOX"
  ;&
4)
  echo "JUMPED"
  ;&
esac

only prints "BROWN"

How do I make the case statement in bash "fall through" to the remaining conditions like the first example?

(edit: Bash version 3.2.25, the ;& statement (from wiki) results in a syntax error)

running:

test.sh:

#!/bin/bash
A=2
case $A in
1)
  echo "QUICK"
  ;&
2)
  echo "BROWN"
  ;&
3)
  echo "FOX"
  ;&
esac

Gives:

> ./test.sh: line 6: syntax error near unexpected token ;' ./test.sh: > line 6: ;&'

Bash Solutions


Solution 1 - Bash

The ;& and ;;& operators were introduced in bash 4.0, so if you want to stick with a five year old version of bash, you'll either have to repeat code, or use ifs.

if (( a == 1)); then echo quick; fi
if (( a > 0 && a <= 2)); then echo brown; fi 
if (( a > 0 && a <= 3)); then echo fox; fi
if (( a == 4)); then echo jumped; fi

or find some other way to achieve the actual goal.

(On a side note, don't use all uppercase variable names. You risk overwriting special shell variables or environment variables.)

Solution 2 - Bash

Try this:

case $VAR in
normal)
    echo "This doesn't do fallthrough"
    ;;
fallthrough)
    echo -n "This does "
    ;&
somethingelse)
    echo "fall-through"
    ;;
esac

Solution 3 - Bash

Using ;& is not very portable, as it requires bash (not ash, dash, or any other minimal sh) and it requires at least bash 4.0 or newer (not available on all systems, e.g. macOS 10.14.6 still only offers bash 3.2.57).

A work around that I consider much nicer to read than a lot of if's is loop and modify the case var:

#!/bin/sh

A=2
A_BAK=$A
while [ -n "$A" ]; do
	case $A in
	    1)
	        echo "QUICK"
	        A=2
	        ;;

	    2)
	        echo "BROWN"
	        A=3
	        ;;

	    3)
	        echo "FOX"
	        A=4
	        ;;

	    4)
	        echo "JUMPED"
	        A=""
	        ;;
	esac
done
A=$A_BAK

Here's a proof of concept: https://www.onlinegdb.com/0ngLPXXn8

Solution 4 - Bash

bash switch with fallthrough, implemented with function and flag

#! /bin/sh

switch_fallthrough() {
  [ $# = 0 ] && { echo no value >&2; return; }
  local f= # fall through
  [ "$1" = 1 ] && { echo quick; f=1; }
  [ $f ] || [ "$1" = 2 ] && { echo brown; f=1; }
  [ $f ] || [ "$1" = 3 ] && { echo fox; return; }
  [ $f ] || [ "$1" = 4 ] && echo jumped
  return 1 # error = no case did match
}

switch_fallthrough "2"
# brown
# fox

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionResorathView Question on Stackoverflow
Solution 1 - BashgeirhaView Answer on Stackoverflow
Solution 2 - BashRené SteetskampView Answer on Stackoverflow
Solution 3 - BashMeckiView Answer on Stackoverflow
Solution 4 - BashMila NautikusView Answer on Stackoverflow