Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I'd like to use variable as condition in case statement. Something similar to:

#!/bin/sh

ALLOWED_SERVICES=tomcat6|james;

case $1 in
    $ALLOWED_SERVICES )
        service $1 restart
    ;;
    * )
    echo "Unsupported argument"
    ;;
esac

This doesn't work. When script is started with tomcat6 argument for exapmle, it outpoots "Unsuported argument" message. But when case condition is hardcoded it works ok:

case $1 in
    tomcat6|james )
        service $1 restart
    ;;
    * )
    echo "Unsupported argument"
    ;;
esac

Is it possible to use variables in this case?

share|improve this question
add comment

4 Answers 4

up vote 1 down vote accepted

Trouble is that both variable expansion and pattern expansion need to be done before matching and that doesn't work here. If you have a recent version of bash available you could use regex matching:

#!/bin/bash

ALLOWED_SERVICES="tomcat6|james"

if [[ $ALLOWED_SERVICES =~ $1 ]]; then
  service $1 restart
else
  echo "Unsupported argument"
fi

Add shopt -s nocasematch before the if to make the matching case insensitive.

share|improve this answer
add comment

The | that separates multiple alternatives is part of the shell syntax. You can't have it come from a string: the string would have to match, with the | character inside.

What you can do is check whether the service name appears as a substring in the list of allowed services, surrounded by delimiters. In other words, check if the list of allowed services contains the service as a substring. Put delimiters around the service name in case it's the first or the last one in the list.

case "$1" in
  *\|*) echo 1>&2 "$0: Invalid service name: $1"; exit 2;;
esac
case "|$ALLOWED_SERVICES|" in
  *"|$1|"*) service "$1" restart;;
  *) echo 1>&2 "$0: Unknown or forbidden service: $1"; exit 2;;
esac
share|improve this answer
add comment

Your first clode block wouldn't work, since it will try to pipe the output of tomcat6 through the command james.

At any rate, case is probably not the right tool for this. Use an array and then check against that:

#!/bin/bash
declare -a ALLOWED_SERVICES
ALLOWED_SERVICES=(james tomcat6)

for servicename in ${ALLOWED_SERVICES[*]};
do
        if [ "${servicename}" == "${1}" ];
        then
          service $1 restart
          exit
        fi

done

echo $0: Error: service \"$1\" not recognized

EDIT: also: use bash :-)

share|improve this answer
    
You use bash, the OP uses sh. –  Tom Regner Sep 7 '12 at 11:51
add comment

You can use variables in case conditions, but you cannot pass alternatives that way. One way to do what you want would be to use eval:

#!/bin/sh

ALLOWED_SERVICES="tomcat6|james";

SERVICE="unknown"
[ -n "$1" ] && SERVICE="$1"

CHECKSRV=$(echo $SERVICE | sed 's/[a-z0-9_]*//i')
[ -n "$CHECKSRV" ] && exit 2


eval "
case \"$SERVICE\" in
    ${ALLOWED_SERVICES} )
        service \"$SERVICE\" restart
    ;;
    * )
    echo \"Unsupported argument\"
    ;;
esac
"

I personally would prefer another solution to using eval, but given the check with the sed filter, you should be good to go.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.