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

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

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

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
...

据我所知,这样做的方法是构造一个像这样的 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

但这当然太复杂了,无法无错误地阅读、理解和编写,因为我的变量名称 ($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

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

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

感谢您的任何帮助。

答案1

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

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

[[ $string == *"$pattern"* ]]

代替

[[ $string =~ $pattern ]]

在下面的代码中。

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

或者,使用包含 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

每个脚本的输出都是

first and second pattern matched

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

答案2

这里与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

zsh相当于bash;;&;|, 还支持者mksh

答案3

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

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

一旦获得数字结果,就应该对其进行算术运算,而不是作为命令运行:

contains_a=$(! [[ $A == *$pattern_a* ]]; echo $?)
contains_b=$(! [[ $A == *$pattern_b* ]]; echo $?)
contains_c=$(! [[ $A == *$pattern_c* ]]; echo $?)

if (( contains_a && contains_b && contains_c )); then
    echo all
elif (( contains_a && contains_b )); then
    echo ab
...
fi

答案4

=~通过在 bash 中使用正则表达式匹配仅测试每个可能的匹配模式一次,可以构建二进制数。为了以正确的顺序构建二进制数(MSB 保留并对应于最后执行的测试),我们需要将(否定的)退出代码添加到变量中。

#!/bin/bash --

string=${1:-"abba"}

patterns=( a b c )

unset bin
for re in "${patterns[@]}"; do
    ! [[ $string =~ $re ]]; bin="$?$bin"
done

case $((2#$bin)) 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

只是先前答案的替代解决方案。

相关内容