Home Switchboard Unix Administration Red Hat TCP/IP Networks Neoliberalism Toxic Managers
May the source be with you, but remember the KISS principle ;-)
Bigger doesn't imply better. Bigger often is a sign of obesity, of lost control, of overcomplexity, of cancerous cells

Case statement in shell



Recommended  Links

Arithmetic expressions Comparison operators String Operations in Shell
if statements Loops in Shell   select   Pipes in Loops
  Advanced navigation BASH Debugging Shell history   Etc

Shell case statement is similar to those in Pascal and switch statement in C. It  can be used to test a variable against set of patterns.  Often case statement lets you express a series of if-then-else statements that check single variable for various conditions or ranges in a more concise way.

The syntax of case is as follows:

case expression in
    pattern1 )
        statements ;;
    pattern2 )
        statements ;;

Any of the patterns can actually be several patterns separated by pipe character "|". If expression matches one of the patterns, its corresponding statements of a case branch are executed. If there are several patterns separated by pipe characters, the expression can match any of them in order for the associated statements to be run. The patterns are checked in order until a match is found; if none is found, nothing happens.

For example:

for filename in $*; do
    case $filename in
        *.c )
            ccom $filename $objname
        *.s )
            as $filename $objname 
        *.o ) ;;
        *   )
            print "error: $filename is not a source or object file."
            return 1 ;;

The final case is *, which is a catchall for whatever didn't match the other cases. (In fact, a * case is analogous to a default case in C and an otherwise case in some Pascal-derived languages.)

Another example:

case $extension in
     "gz" )
           gunzip $file
     "bz2" )
           bz2unpack $file
     * )
           echo "Archive format for extention '$extension' is not recognized."

Above, bash first expands "${file##*.}". In the code, "$file" is the name of a file, and "${file##.*}" has the effect of stripping all text except that following the last period in the filename. Then, bash compares the resultant string against the values listed cases of case statement. In this case, file extension will be  compared against "gz" and "bz2" If one of those matches, then appropriate command will be executed for the value of $file .

Please note that  $file can contain fully qualified filename . For example:


Extension will still be extracted correctly. Of course you can split fully qualified name into directory and path and operate with them separately, for example:

file=$(basename $fully_qualified_name)
dir=$(dirname $fully_qualified_name)

So far selectors in case statement were simple strings. They can be pretty complex patterns. For example here is how you can implement the functions that trims spaces both from left and right of its argument:

function trim
   while : # this is an infinite loop
   case $target in
      ' '*) target=${target#?} ;; ## if $target begins with a space remove it
      *' ') target=${target%?} ;; ## if $target ends with a space remove it
      *) break ;; # no more leading or trailing spaces, so exit the loop
   return target

You can use "Or" operation in case to tie several cases to one branch of case statement. Here is an example from Wikipedia:

case $n in
    0)      echo 'You typed 0.';;
    1|9)    echo "$n is a perfect square.";;
    3|5|7)  echo "$n is a prime number.";;
    4)    echo "$n is a perfect square.
$n is an even number";;
    2|6|8)    echo "$n is an even number.";;
    *)      echo 'Only single-digit numbers are allowed.';;
As patterns can have character classes that sometimes simplify logic or options processing and similar cases (Using case statements):

# This script does a very simple test for checking disk space.

space=`df -h | awk '{print $5}' | grep % | grep -v Use | sort -n | tail -1 | cut -d "%" -f1 -`

case $space in
  Message="All is quiet."
  Message="Start thinking about cleaning out some stuff.  There's a partition that is $space % full."
  Message="Better hurry with that new disk...  One partition is $space % full."
  Message="I'm drowning here!  There's a partition at $space %!"
  Message="I seem to be running with an nonexistent amount of disk space..."

Additional examples from Advanced Bash-Scripting Guide

Here are few additional examples from Advanced Bash-Scripting Guide: Chapter 11. Loops and Branches

Example 11-24. Using case
# Testing ranges of characters.

echo; echo "Hit a key, then hit return."
read Keypress

case "$Keypress" in
  [[:lower:]]   ) echo "Lowercase letter";;
  [[:upper:]]   ) echo "Uppercase letter";;
  [0-9]         ) echo "Digit";;
  *             ) echo "Punctuation, whitespace, or other";;
esac      #  Allows ranges of characters in [square brackets],
          #+ or POSIX ranges in [[double square brackets.

#  In the first version of this example,
#+ the tests for lowercase and uppercase characters were
#+ [a-z] and [A-Z].
#  This no longer works in certain locales and/or Linux distros.
#  POSIX is more portable.
#  Thanks to Frank Wang for pointing this out.

#  Exercise:
#  --------
#  As the script stands, it accepts a single keystroke, then terminates.
#  Change the script so it accepts repeated input,
#+ reports on each keystroke, and terminates only when "X" is hit.
#  Hint: enclose everything in a "while" loop.

exit 0
Example 11-25. Creating menus using case

# Crude address database

clear # Clear the screen.

echo "          Contact List"
echo "          ------- ----"
echo "Choose one of the following persons:" 
echo "[E]vans, Roland"
echo "[J]ones, Mildred"
echo "[S]mith, Julie"
echo "[Z]ane, Morris"

read person

case "$person" in
# Note variable is quoted.

  "E" | "e" )
  # Accept upper or lowercase input.
  echo "Roland Evans"
  echo "4321 Flash Dr."
  echo "Hardscrabble, CO 80753"
  echo "(303) 734-9874"
  echo "(303) 734-9892 fax"
  echo ""
  echo "Business partner & old friend"
# Note double semicolon to terminate each option.

  "J" | "j" )
  echo "Mildred Jones"
  echo "249 E. 7th St., Apt. 19"
  echo "New York, NY 10009"
  echo "(212) 533-2814"
  echo "(212) 533-9972 fax"
  echo ""
  echo "Ex-girlfriend"
  echo "Birthday: Feb. 11"

# Add info for Smith & Zane later.

          * )
   # Default option.	  
   # Empty input (hitting RETURN) fits here, too.
   echo "Not yet in database."



#  Exercise:
#  --------
#  Change the script so it accepts multiple inputs,
#+ instead of terminating after displaying just one address.

exit 0

An  clever use of case involves testing for command-line parameters.

#! /bin/bash

case "$1" in
  "") echo "Usage: ${0##*/} <filename>"; exit $E_PARAM;;
                      # No command-line parameters,
                      # or first parameter empty.
# Note that ${0##*/} is ${var##pattern} param substitution.
                      # Net result is $0.

  -*) FILENAME=./$1;;   #  If filename passed as argument ($1)
                      #+ starts with a dash,
                      #+ replace it with ./$1
                      #+ so further commands don't interpret it
                      #+ as an option.

  * ) FILENAME=$1;;     # Otherwise, $1.

Here is an more straightforward example of command-line parameter handling:

#! /bin/bash

while [ $# -gt 0 ]; do    # Until you run out of parameters . . .
  case "$1" in
              # "-d" or "--debug" parameter?
              if [ ! -f $CONFFILE ]; then
                echo "Error: Supplied file doesn't exist!"
                exit $E_CONFFILE     # File not found error.
  shift       # Check next set of parameters.

#  From Stefano Falsetto's "Log2Rot" script,
#+ part of his "rottlog" package.
#  Used with permission.
Example 11-26. Using command substitution to generate the case variable
# Using command substitution to generate a "case" variable.

case $( arch ) in   # "arch" returns machine architecture.
                    # Equivalent to 'uname -m' ...
  i386 ) echo "80386-based machine";;
  i486 ) echo "80486-based machine";;
  i586 ) echo "Pentium-based machine";;
  i686 ) echo "Pentium2+-based machine";;
  *    ) echo "Other type of machine";;

exit 0

A case construct can filter strings for globbing patterns.

Example 11-27. Simple string matching
# Simple string matching.

match_string ()
{ # Exact string match.
  PARAMS=2     # Function requires 2 arguments.

  [ $# -eq $PARAMS ] || return $E_BAD_PARAMS

  case "$1" in
  "$2") return $MATCH;;
  *   ) return $E_NOMATCH;;



match_string $a     # wrong number of parameters
echo $?             # 91

match_string $a $b  # no match
echo $?             # 90

match_string $b $d  # match
echo $?             # 0

exit 0		    
Example 11-28. Checking for alphabetic input
# Using a "case" structure to filter a string.


isalpha ()  # Tests whether *first character* of input string is alphabetic.
if [ -z "$1" ]                # No argument passed?
  return $FAILURE

case "$1" in
  [a-zA-Z]*) return $SUCCESS;;  # Begins with a letter?
  *        ) return $FAILURE;;
}             # Compare this with "isalpha ()" function in C.

isalpha2 ()   # Tests whether *entire string* is alphabetic.
  [ $# -eq 1 ] || return $FAILURE

  case $1 in
  *[!a-zA-Z]*|"") return $FAILURE;;
               *) return $SUCCESS;;

isdigit ()    # Tests whether *entire string* is numerical.
{             # In other words, tests for integer variable.
  [ $# -eq 1 ] || return $FAILURE

  case $1 in
    *[!0-9]*|"") return $FAILURE;;
              *) return $SUCCESS;;

check_var ()  # Front-end to isalpha ().
if isalpha "$@"
  echo "\"$*\" begins with an alpha character."
  if isalpha2 "$@"
  then        # No point in testing if first char is non-alpha.
    echo "\"$*\" contains only alpha characters."
    echo "\"$*\" contains at least one non-alpha character."
  echo "\"$*\" begins with a non-alpha character."
              # Also "non-alpha" if no argument passed.



digit_check ()  # Front-end to isdigit ().
if isdigit "$@"
  echo "\"$*\" contains only digits [0 - 9]."
  echo "\"$*\" has at least one non-digit character."



e=`echo $b`   # Command substitution.

check_var $a
check_var $b
check_var $c
check_var $d
check_var $e
check_var $f
check_var     # No argument passed, so what happens?
digit_check $g
digit_check $h
digit_check $i

exit 0        # Script improved by S.C.

# Exercise:
# --------
#  Write an 'isfloat ()' function that tests for floating point numbers.
#  Hint: The function duplicates 'isdigit ()',
#+ but adds a test for a mandatory decimal point.

Top Visited
Past week
Past month


Old News ;-)

[Feb 10, 2011] Regex in if-then-else statement to match strings

Sept 18, 2007 | The UNIX and Linux Forums

Using a case/esac statement makes regular expressions simple and obvious.


case $name in
    [ab]{2,3} )
         echo do stuff
    * ) 



Perhaps I am using a too-old version of bash. Version 3.00.16(1) recognizes the [ab] but not the {2,3} part, apparently because the case selectors are expanded in the same fashion as pathnames, not regular expressions:



# @(#) s4       Demonstrate case selectors.

set -o nounset

echo "GNU bash $BASH_VERSION" >&2
# See:


# if [ $name = [ab]{2,3} ]; then
echo " Original string = \"$name\""

case $name in
[ab]{2,3} )
    echo Success
* )
    echo Failure

echo " Original string = \"$name\""

case $name in
[ab]{2,3} )
    echo Success
* )
    echo Failure

exit 0



% ./s4

GNU bash 3.00.16(1)-release

 Original string = "bb"

 Original string = "b{2,3}"

cheers, drl


Yes, it's globbing, not re's. For {2,3} with globbing:


bash 3.2.25(1)$ v=b
bash 3.2.25(1)$ case $v in ([ab][ab]|[ab][ab][ab]) echo OK;;(?) echo KO;;esac
bash 3.2.25(1)$ v=bbb
bash 3.2.25(1)$ case $v in ([ab][ab]|[ab][ab][ab]) echo OK;;(?) echo KO;;esac
bash 3.2.25(1)$ # or:
bash 3.2.25(1)$ shopt -s extglob
bash 3.2.25(1)$ v=b
bash 3.2.25(1)$ case $v in ([ab][ab]?([ab])) echo OK;;(?) echo KO;;esac
bash 3.2.25(1)$ v=bb
bash 3.2.25(1)$ case $v in ([ab][ab]?([ab])) echo OK;;(?) echo KO;;esac

[Feb 10, 2011] Idiosyncratic behavior-case-statement-bash

08-20-2008 | The UNIX and Linux Forums


Hello all, I'm a new poster with a problem that I'm not finding in the archives.

I'm trying to better my understanding of the behavior of case statements, in particular the word to pattern matching aspects. According to the GNU bash reference (Bash Reference Manual) the syntax is:
case word in [ [(] pattern [| pattern]...) command-list ;;]... esac

Also, "Each pattern undergoes tilde expansion, parameter expansion, command substitution, and arithmetic expansion."

Based on this I would expect both of these expressions to behave identically:

#! /bin/bash
# test program attempting to understand case statements
# predominantly used/tested by author in bash --version
#    GNU bash, version 3.2.39(1)-release (i686-pc-linux-gnu)
#    Copyright (C) 2007 Free Software Foundation, Inc.
# please note that above version is as installed by gentoo
# also tested using completely unmodified/unpatched bash --version 
#    GNU bash, version 3.2.0(1)-release (i686-pc-linux-gnu)
#    Copyright (C) 2005 Free Software Foundation, Inc.

# Usage: $0 [ {1..10} ]


if [ $# -gt 0 ]

echo VAR=$VAR

case $VAR in
   [1..5] ) echo "one to five" ;;
  $(seq -s'|' 6 10) ) echo "six to ten" ;;
#  6|7|8|8|10 ) echo "six to ten" ;;
  *       ) echo "fall through" ;;

exit 0


Interesting. I replaced seq with echo "6|7|8|9|10" just to take seq out of the equation. The script works as expected with ksh93 but fails on bash (version 3.2.29)


It seems to interpret the expanded string literally.


bash$ case '6|7|8|9|10' in $(seq -s '|' 6 10) ) echo yes;; esac

It would surprise me if the spec is unambiguous on this point ...



It seems to interpret the expanded string literally.


bash$ case '6|7|8|9|10' in $(seq -s '|' 6 10) ) echo yes;; esac

It would surprise me if the spec is unambiguous on this point ...

You nailed it. Sifting through the source was revealing:

case 3 in 2|3|4 )

The above produces a linked list of strings 2->3->4, which are in turn compared as strings against the 3 in the case. When a variable or command substitution is used the substitution happens but is never parsed for comparison of individual components.

This appears to be a bug and has been submitted as such.



shopt -s extglob
case $var in
    @($(seq -s'|' 6 10)) )   echo "six to ten" ;;
    6|7|8|8|10 ) echo "dfs six to ten" ;;
shopt -u extglob

See here under for explanation



My interpretation of this is different from the previous ones. The bash manual does indeed have the words cited. And it is clear that substitution takes place. However, the result is simply a string. The manual does not say that the case statement is then re-scanned to cause the strings to be treated as patterns.

We know how to cause a re-scan: the eval built-in:

Code: #!/bin/bash3 -

# @(#) s2 Demonstrate eval of case to get active selectors.

echo echo "(Versions displayed with local utility \"version\")" version >/dev/null 2>&1 && version "=o" $(_eat $0 $1) set -o nounset

echo VAR=6

if [ $# -gt 0 ] then VAR=$1 fi

echo VAR=$VAR six=$(seq -s'|' 6 10) echo " Generated selector in variable: $six"

echo echo " Results of eval case:" eval " case $VAR in $(seq -s'|' 1 5) ) echo ' 1 - 5 (seq)' ;; $six) echo 'six to ten (variable)' ;; * ) echo 'fall through' ;; esac "

exit 0 Producing:

Code: $ ./s2 5

(Versions displayed with local utility "version") Linux 2.6.11-x1 GNU bash 3.00.16(1)-release

VAR=5 Generated selector in variable: 6|7|8|9|10

Results of eval case: 1 - 5 (seq) $ $ ./s2 7

(Versions displayed with local utility "version") Linux 2.6.11-x1 GNU bash 3.00.16(1)-release

VAR=7 Generated selector in variable: 6|7|8|9|10

Results of eval case: six to ten (variable) This may not be what we want or expect, and the interpretation may not even be correct. We might consider this a method to get around a limitation. In any case (pun intended), it works ... cheers, drl

Shell Programming Introduction

Recommended Links

Google matched content

Softpanorama Recommended

Top articles




Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers :   Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism  : The Iron Law of Oligarchy : Libertarian Philosophy


War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda  : SE quotes : Language Design and Programming Quotes : Random IT-related quotesSomerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose BierceBernard Shaw : Mark Twain Quotes


Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 :  Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method  : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law


Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds  : Larry Wall  : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOSProgramming Languages History : PL/1 : Simula 67 : C : History of GCC developmentScripting Languages : Perl history   : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history

Classic books:

The Peter Principle : Parkinson Law : 1984 : The Mythical Man-MonthHow to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Haterís Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite

Most popular humor pages:

Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor

The Last but not Least Technology is dominated by two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt. Ph.D

Copyright © 1996-2018 by Dr. Nikolai Bezroukov. was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP) in the author free time and without any remuneration. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.

This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...

You can use PayPal to make a contribution, supporting development of this site and speed up access. In case is down you can use the at


The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the author present and former employers, SDNP or any other organization the author may be associated with. We do not warrant the correctness of the information provided or its fitness for any purpose.

The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.

Last modified: September 12, 2017