bash 中的动态 case 语句

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4687722/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 23:15:51  来源:igfitidea点击:

Dynamic case statement in bash

bashscriptingbash-completion

提问by infra.user

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

我想弄清楚如何在 bash 脚本中创建动态 case 语句。

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

例如,假设我有一个带有以下内容的 awk 语句的输出

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.

如果此 awk 输出中包含一个值,我将尝试执行不同的逻辑。

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

因此,如果上面的数据在 $list 中,那么我会在概念上执行以下操作:

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_2for some background).

我正在尝试使用它来构建动态自定义选项卡完成功能(有关某些背景,请参阅http://www.debian-administration.org/article/An_introduction_to_bash_completion_part_2)。

Any ideas?

有任何想法吗?

Thanks.

谢谢。

回答by Jason H

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

您可以通过执行以下操作在 bash 中创建动态 case 语句:

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

1) 确保列表以 PIPE (|) 分隔。IE。红色|绿色|蓝色

2) wrap your case statement in an eval

2) 将您的 case 语句包装在一个 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.

这适用于简单的变量处理,我不能保证这在所有情况下都有效。

回答by Charles Duffy

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.

你不能用 case 语句来做到这一点,但设置你自己的助手来检查列表成员资格是很容易的。

# stub to simulate this arbitrary call
my_awk_command() { printf '%s\n' red green blue; }
# helper to check list membership
list_contains() {
  local tgt=""; shift
  while (( $# )); do
    if [[  = "$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

回答by John Kugelman

A casestatement is probably not the right tool for the job. If you store the awkoutput 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.

一个case说法可能是不适合这份工作的合适工具。如果您将awk输出存储在一个数组中,那么您可以遍历该数组以查找其中是否有一个选项,作为奖励,您还可以找出是哪个索引。

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

回答by Paused until further notice.

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

您可以通过几种不同的hacky方式来解决这个问题:

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