我有一个脚本,需要在字符串变量的内容之间进行所有可能的比较。每种组合都需要对变量的内容采用不同的方法,因此如下所示:
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
答案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
只是先前答案的替代解决方案。