将布尔比较的值分配给变量

Zai*_*ida 7 scripting bash shell-script

我有一个脚本,需要在字符串变量的内容之间进行所有可能的比较。每种组合都需要对变量的内容采用不同的方法,因此如下所示:

if $a contains "a" AND "b" AND "c"; then do x
elif $a contains "a" AND "b" but NOT "c"; then do y
elif $a contains "b" AND "c" but NOT "a"; then do z
...
Run Code Online (Sandbox Code Playgroud)

据我所知,这样做的方法是构造一个像这样的 if 条件:

if [[ $A == *"b"* ]] && [[ $A == *"c"* ]] && [[ $A == *"d"* ]]
elif [[ $A == *"b"* ]] && [[ $A == *"c"* ]]
elif [[ $A == *"c"* ]] && [[ $A == *"d"* ]]
elif [[ $A == *"b"* ]] && [[ $A == *"d"* ]]
elif [[ $A == *"b"* ]]
elif [[ $A == *"c"* ]]
elif [[ $A == *"d"* ]]
fi
Run Code Online (Sandbox Code Playgroud)

但这当然太复杂了,无法无错误地阅读、理解和编写,因为我的变量名称 ($A) 和子字符串 (b, c, d) 比这长得多。所以我想看看是否有一种方法可以将条件表达式的内容保存到变量中:

contains_b= *a condition for [[ $A == *"b"* ]]*; echo $contains_b-> 真实 | 错误的

我只在这里找到了回复[ contains_b=$(! [ "$A" = *"b"* ]; echo $?)];但是,$contains_b -> 0在后续条件中不起作用,因为:

if $contains_b; then do x; fi->bash: [0]: command not found

所以我能想到的唯一解决方案是手动完成:

if [[ $A == *"b"* ]]; then
    contains_b=true
else
    contains_b=false
fi
Run Code Online (Sandbox Code Playgroud)

然而,我最终会执行三个 if 语句来获取三个变量,并对每个不同的组合进行其他 7 次比较。

我想知道是否有不同/更有效的方法来做到这一点。如果没有,您对进行多重比较的另一种方法有什么建议吗?我感觉我把事情搞得太复杂了...

感谢您的任何帮助。

Kus*_*nda 8

创建一个二进制掩码,然后对其进行操作。这样做的好处是每个测试只执行一次,并且它将测试与对测试结果进行操作分开。

请注意,代码使用模式作为扩展正则表达式。要将它们作为字符串进行比较,请使用

[[ $string == *"$pattern"* ]]
Run Code Online (Sandbox Code Playgroud)

代替

[[ $string =~ $pattern ]]
Run Code Online (Sandbox Code Playgroud)

在下面的代码中。

patterns=( a b c )
string='abba'

mask=0; i=0
for pattern in "${patterns[@]}"; do
        if [[ $string =~ $pattern ]]; then
                # setting the i:th bit from the right to one
                mask=$(( mask | (1 << i) ))
        fi
        i=$(( i + 1 ))
done

case $mask in
        0) echo no match ;;
        1) echo first pattern matched ;;
        2) echo second pattern matched ;;
        3) echo first and second pattern matched ;;
        4) echo third pattern matched ;;
        5) echo first and third pattern matched ;;
        6) echo second and third pattern matched ;;
        7) echo all patterns matched ;;
        *) echo error
esac
Run Code Online (Sandbox Code Playgroud)

或者,使用包含 1 和 0 的字符串掩码(0 表示不匹配,1 表示匹配)。请注意,下面的字符串与mask上面代码中使用的数字的实际二进制表示形式相反。

patterns=( a b c )
string='abba'

unset -v mask
for pattern in "${patterns[@]}"; do
        ! [[ $string =~ $pattern ]]
        # string concatenation of the exit status of the previous command
        mask+=$?
done

case $mask in
        000) echo no match ;;
        100) echo first pattern matched ;;
        010) echo second pattern matched ;;
        110) echo first and second pattern matched ;;
        001) echo third pattern matched ;;
        101) echo first and third pattern matched ;;
        011) echo second and third pattern matched ;;
        111) echo all patterns matched ;;
        *) echo error
esac
Run Code Online (Sandbox Code Playgroud)

每个脚本的输出都是

first and second pattern matched
Run Code Online (Sandbox Code Playgroud)

...因为该字符串abba与前两个模式匹配,a并且b.


Sté*_*las 6

这里使用bash4.0或更高版本或mkshR40case或更高版本,您可以通过两条语句完成所有操作:

a=n b=n c=n
case $string in
  (*a*) a=y ;;&
  (*b*) b=y ;;&
  (*c*) c=y
esac
case $a$b$c in
  (nnn) echo none   ;;
  (ynn) echo a only ;;
  (yyn) echo ab     ;;
  (yyy) echo all    ;;
    (*) echo other
esac
Run Code Online (Sandbox Code Playgroud)

相当于zshbashis ;;&;|mksh.