118

I have a Bash script that performs actions based on the value of a variable. The general syntax of the case statement is:

case ${command} in
   start)  do_start ;;
   stop)   do_stop ;;
   config) do_config ;;
   *)      do_help ;;
esac

I'd like to execute a default routine if no command is provided, and do_help if the command is unrecognized. I tried omitting the case value thus:

case ${command} in
   )       do_default ;;
   ...
   *)      do_help ;;
esac

The result was predictable, I suppose:

syntax error near unexpected token `)'

Then I tried using a regex:

case ${command} in
   ^$)     do_default ;;
   ...
   *)      do_help ;;
esac

With this, an empty ${command} falls through to the * case.

Am I trying to do the impossible?

1
  • how is the command being provided? through stdin? Commented Jul 10, 2013 at 16:04

3 Answers 3

175

The case statement uses globs, not regexes, and insists on exact matches.

So the empty string is written, as usual, as "" or '':

case "$command" in
  "")        do_empty ;;
  something) do_something ;;
  prefix*)   do_prefix ;;
  *)         do_other ;;
esac
Sign up to request clarification or add additional context in comments.

3 Comments

As a note, this works as well when using multiple choices: something|'') do_something ;;
Perhaps explain in your answer why $command is quoted? (But without "Edit:", "Update:", or similar - the answer should appear as if it was written today.)
@PeterMortensen: in shell scripting, what demands explanation is the absence of quotes; quoting expansions goes without saying. I could have left the quotes out, but I chose not to and thus didn't have to explain why it's possible to do so. (And I'm not actually 100% sure that no corner cases exist.)
6

I use a simple fall through. no parameters passed ($1="") will be caught by the second case statement, yet the following * will catch any unknown parameter. Flipping the "") and *) will not work as *) will catch everything every time in that case, even blanks.

#!/usr/local/bin/bash
# testcase.sh
case "$1" in
  abc)
    echo "this $1 word was seen."
    ;;
  "") 
    echo "no $1 word at all was seen."
    ;;
  *)
    echo "any $1 word was seen."
    ;;
esac

Comments

1

Here's how I do it (to each their own):

#!/bin/sh

echo -en "Enter string: "
read string
> finder.txt
echo "--" >> finder.txt

for file in `find . -name '*cgi'`

do

x=`grep -i -e "$string" $file`

case $x in
"" )
     echo "Skipping $file";
;;
*)
     echo "$file: " >> finder.txt
     echo "$x" >> finder.txt
     echo "--" >> finder.txt
;;
esac

done

more finder.txt

If I am searching for a subroutine that exists in one or two files in a filesystem containing dozens of cgi files I enter the search term, e.g. 'ssn_format'. bash gives me back the results in a text file (finder.txt) that looks like this:

-- ./registry/master_person_index.cgi: SQLClinic::Security::ssn_format($user,$script_name,$local,$Local,$ssn) if $ssn ne "";

1 Comment

Re "Here's how I do it": Why do you do it that way? And how is it different from the other answers? Preferably, please respond by editing your answer (without "Edit:", "Update:", or similar - the question/answer should appear as if it was written today).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.