Softpanorama
May the source be with you, but remember the KISS principle ;-)

Contents Bulletin Scripting in shell and Perl Network troubleshooting History Humor

Case statement in shell

News

bash

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 ;;
    ...
esac

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 )
            objname=${filename%.c}.o
            ccom $filename $objname
            ;;
        *.s )
            objname=${filename%.s}.o
            as $filename $objname 
            ;;
        *.o ) ;;
        *   )
            print "error: $filename is not a source or object file."
            return 1 ;;
    esac
done

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:

 
extension="${file##*.}" 
case $extension in
     "gz" )
           gunzip $file
           ;;
     "bz2" )
           bz2unpack $file
           ;;
     * )
           echo "Archive format for extention '$extension' is not recognized."
           ;;
esac

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:

file="/somewhere/sample.gz"

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
{ 
   target=$1
   while : # this is an infinite loop
   do
   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
   esac
   done
   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.';;
esac
As patterns can have character classes that sometimes simplify logic or options processing and similar cases (Using case statements):
cat disktest.sh
#!/bin/bash

# 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
[1-6]*)
  Message="All is quiet."
  ;;
[7-8]*)
  Message="Start thinking about cleaning out some stuff.  There's a partition that is $space % full."
  ;;
9[1-8])
  Message="Better hurry with that new disk...  One partition is $space % full."
  ;;
99)
  Message="I'm drowning here!  There's a partition at $space %!"
  ;;
*)
  Message="I seem to be running with an nonexistent amount of disk space..."
  ;;
esac

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
#!/bin/bash
# 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
#!/bin/bash

# Crude address database

clear # Clear the screen.

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

read person

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

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

  "J" | "j" )
  echo
  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 "milliej@loisaida.com"
  echo "Ex-girlfriend"
  echo "Birthday: Feb. 11"
  ;;

# Add info for Smith & Zane later.

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

esac

echo

#  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.
esac

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|--debug)
              # "-d" or "--debug" parameter?
              DEBUG=1
              ;;
    -c|--conf)
              CONFFILE="$2"
              shift
              if [ ! -f $CONFFILE ]; then
                echo "Error: Supplied file doesn't exist!"
                exit $E_CONFFILE     # File not found error.
              fi
              ;;
  esac
  shift       # Check next set of parameters.
done

#  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
#!/bin/bash
# case-cmd.sh: 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";;
esac

exit 0

A case construct can filter strings for globbing patterns.

Example 11-27. Simple string matching
#!/bin/bash
# match-string.sh: Simple string matching.

match_string ()
{ # Exact string match.
  MATCH=0
  E_NOMATCH=90
  PARAMS=2     # Function requires 2 arguments.
  E_BAD_PARAMS=91

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

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

}  


a=one
b=two
c=three
d=two


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
#!/bin/bash
# isalpha.sh: Using a "case" structure to filter a string.

SUCCESS=0
FAILURE=-1

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

case "$1" in
  [a-zA-Z]*) return $SUCCESS;;  # Begins with a letter?
  *        ) return $FAILURE;;
esac
}             # 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;;
  esac
}

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;;
  esac
}



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

echo

}

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

echo

}

a=23skidoo
b=H3llo
c=-What?
d=What?
e=`echo $b`   # Command substitution.
f=AbcDef
g=27234
h=27a34
i=27.34

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 updates

Shop Amazon Cyber Monday Deals Week
Google Search


NEWS CONTENTS

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.

Code:

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

drl:

Hi.

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:

Code:

#!/bin/bash3

# @(#) s4       Demonstrate case selectors.

set -o nounset
echo

echo "GNU bash $BASH_VERSION" >&2
echo " MUST USE VERSION 3 FOR REGULAR EXPRESSIONS WITH =~ OPERATOR!"
# See: http://www.unix.com/showthread.php?p=302136557&posted=1#post302136557

echo

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

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

echo
name="b{2,3}"
echo " Original string = \"$name\""

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

exit 0

producing:

Code:

% ./s4

GNU bash 3.00.16(1)-release
 MUST USE VERSION 3 FOR REGULAR EXPRESSIONS WITH =~ OPERATOR!

 Original string = "bb"
Failure

 Original string = "b{2,3}"
Success

cheers, drl

radoulov:

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

Code:

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
KO
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
OK
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
KO
bash 3.2.25(1)$ v=bb
bash 3.2.25(1)$ case $v in ([ab][ab]?([ab])) echo OK;;(?) echo KO;;esac
OK

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

08-20-2008  | The UNIX and Linux Forums

stryth

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} ]


VAR=6

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

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" ;;
esac

exit 0

fpmurphy

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) 

era

It seems to interpret the expanded string literally.

Code:

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

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

stryth

Quote:

It seems to interpret the expanded string literally.

Code:

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

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.

ghostdog74:

Code:

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

See here under 3.5.8.1 for explanation

drl

Hi.

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

Softpanorama Top Visited

Softpanorama Recommended




Etc

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 in our efforts to advance understanding of environmental, political, human rights, economic, democracy, scientific, and social justice issues, etc. We believe this constitutes a 'fair use' of any such copyrighted material as provided for in section 107 of the US Copyright Law. In accordance with Title 17 U.S.C. Section 107, the material on this site is distributed without profit exclusivly for research and educational purposes.   If you wish to use copyrighted material from this site for purposes of your own that go beyond 'fair use', you must obtain permission from the copyright owner.

Society

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

Quotes

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

Bulletin:

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

History:

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


Copyright © 1996-2014 by Dr. Nikolai Bezroukov. www.softpanorama.org was created as a service to the UN Sustainable Development Networking Programme (SDNP) in the author free time. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Site uses AdSense so you need to be aware of Google privacy policy. 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 hosting of this site with different providers to distribute and speed up access. Currently there are two functional mirrors: softpanorama.info (the fastest) and softpanorama.net.

Disclaimer:

The statements, views and opinions presented on this web page are those of the author 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.

Last modified: February 19, 2014