English 中文(简体)
Dynamic case statement in bash
原标题:

I m trying to figure out how to create a dynamic case statement in a bash script.

For example, let s say I have the output of an awk statement with the following contents

red
green
blue

In this scenario, the output can change at any time.

I m trying to then execute different logic if a value is included in this awk output.

So if the data above is in $list, then I d conceptually like to do something like:

case "${my_var}" in
    $list)
        .....
    something_else)
        .....
esac

I m trying to use this to build a dynamic custom tab completion function (see http://www.debian-administration.org/article/An_introduction_to_bash_completion_part_2 for some background).

Any ideas?

Thanks.

最佳回答

A case statement is probably not the right tool for the job. If you store the awk output in an array then you can loop through the array to find if a choice is in it, and as a bonus can figure out which index that is, too.

#!/bin/bash

# Store command output in an array so each word is a separate array item.    
list=($(echo $ red
green
blue ))
my_var=blue

for ((i = 0; i < ${#list}; i++)); do
    if [[ ${list[$i]} = $my_var ]]; then
        echo "found at index $i"
        break
    fi
done

if ((i == ${#list})); then
    echo "not found"
fi
问题回答

You can create a dynamic case statement in bash by doing the following:

1) ensure the list is PIPE (|) seperated. IE. red|green|blue

2) wrap your case statement in an eval

For example:

valid="red|green|blue"

eval "case "$choice" in
    $valid)
        echo do something good here
        ;;
    *)
        echo invalid colour
        ;;
esac"

This works for simple variable processing, I can not guarantee this will work in all cases.

You can t do this with a case statement, but it s easy enough to set up your own helper to check for list membership.

# stub to simulate this arbitrary call
my_awk_command() { printf  %s
  red green blue; }
# helper to check list membership
list_contains() {
  local tgt="$1"; shift
  while (( $# )); do
    if [[ $1 = "$tgt" ]] ; then
      return 0
    fi
    shift
  done
  return 1
}

# the below is Bash 4 functionality; see BashFAQ #1 on how to replace it
readarray -t awk_output < <(my_awk_command)

if list_contains "$my_var" "${my_awk_command[@]}"; then
  ...something...
elif [[ "$my_var" = something_else ]] ; then
  ...something else...
fi

You can approach this in a couple of different hacky ways:

pattern=($(awk_command))     # red
green
blue

saveIFS=$IFS
IFS= | 
pattern="^(${pattern[*]})$"  # ^(red|green|blue)$  (perhaps hackish)
IFS=$saveIFS

# simple regex match if statement (not hackish)
if [[ $var =~ $pattern ]]
then
    do_something
fi

# or a backwards case statement (very hackish)
case 1 in    # this could be a variable or a command substitution
    $([[ $var =~ $pattern]] && echo 1) )  # the echo 1 could be another command or the 1 could be yet another variable
        do_something;;
    * )
        do_default;;
esac

This is quite simple to manage with the standard tools available in bash 4. The size of array OptionList can vary freely.

OptionList=(Fred Wilma Barney)
PS3= Choose a character :  
select opt in "${OptionList[@]}" "Quit"; do
    case "$REPLY" in
        $((${#OptionList[@]}+1))) echo "Goodbye!"; exit;;
    esac
    [ $REPLY -gt $((${#OptionList[@]}+1)) -o $REPLY -lt 1 ] && echo "Invalid selection" || break
done

echo "you chose ${OptionList[(($REPLY-1))]}"

might you have to try, sorry if this might to be oot/didnt you guys looking for, (but i think it s help me out) here i have same issues to using wheter sh case with dynamic statement

whereas i have running some function with dynamic listed parameter as input then if there s no function inside/available, it will return exit 1 or "requested not available"

here we go.

myfuncA(){
   echo this funcA
}

myfuncB(){
   echo this funcB
}


dynamicCase(){
   for areWe in $1; do
      my$areWe && echo "$areWe success" || echo "no function $1 available"
   done
}

anotherDyCase(){
   while IFS=read -r $areWe; do
      my$areWe && echo "$areWe success" || echo "no function $1 "
   done <<< $1
}

test ride:

myListedDynamic="funcA
funcB
funcC"
// funcA funcB funcC


dynamicCase $myListedDynamic
// success
// success
// no function available

furthermore

hope help

Cross posted from here...

For recent versions of bash, you can use the non-short-circuiting ;;& operator; it s not case directly supporting arrays in its clauses, but it s reasonably elegant:

ARR=( opt1 opt2 opt3 );

case $1 in
    *)
        [[ ${ARR[*]} =~ $1 ]] 
            && echo "Option is contained in the array" 
            && exit 0
        ;;&

    *)
        echo "Option is not contained in the array"
        ;;
esac

Note ;;& (i.e. non-short circuiting) ensures the $1 is evaluated against subsequent case-clauses; this requires the exit 0 (use return 0 in a function/sourced file) to skip subsequent





相关问题
What does it mean "to write a web service"?

I just asked a question about whether it was possible to write a web-page-checking code and run it from free web server, and one supporter answered and said that it was possible only if I run "a web ...

How can I use exit codes to run shell scripts sequentially?

Since cruise control is full of bugs that have wasted my entire week, I have decided the existing shell scripts I have are simpler and thus better. Here is what I have so far svn update /var/www/...

Dynamically building a command in bash

I am construcing a command in bash dynamically. This works fine: COMMAND="java myclass" ${COMMAND} Now I want to dynamically construct a command that redirectes the output: LOG=">> myfile.log ...

Why does Scala create a ~/tmp directory when I run a script?

When I execute a Scala script from the command line, a directory named "tmp" is created in my home directory. It is always empty, so I simply deleted it without any apparent problem. Of course, when I ...

Ivy, ant and start scripts

I have a project that uses ant to build and ivy for dependencies. I would like to generate the start scripts for my project, with the classpath, based on the dependencies configured in Ivy, ...

热门标签