开发者

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 l开发者_如何学Pythonike 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.


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.


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\ngreen\nblue'))
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'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\n' 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\ngreen\nblue\n
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\nfuncB\nfuncC"
// 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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜