我写了以下bash代码:
NStep=25
NTotal=435
Redone=('375' '400' '425' 'last')
for i in $(seq 0 $NStep $NTotal)
do
if [[ "${Redone[@]}" =~ "$i" ]]; then
echo "do something"
else
echo "do something else"
fi
done
但是,对于步骤0
,25
和75
,它会输入if
语句(并执行某些操作),而我希望它输入else语句(并做其他事情)。如何使我的正则表达式更具体或重写if语句?
谢谢
答案 0 :(得分:2)
在bash中,正则表达式不必匹配整个字符串。您需要说数字应该用空格或字符串的开头或结尾包装:
if [[ "${Redone[@]}" =~ (^| )"$i"( |$) ]]; then
答案 1 :(得分:1)
使用关联数组,而不是索引数组。 (此外,请勿使用seq
;而应使用C样式的循环。)
NStep=25
NTotal=435
declare -A Redone=([375]= [400]= [425]= [last]=)
for ((i=0; i<= $NTotal; i+=$NStep))
do
if [[ -v Redone[$i] ]]; then
echo "do something"
else
echo "do something else"
fi
done
关联数组的键的作用类似于集合,-v
(此处用于测试数组中是否存在给定键)充当成员运算符。
对于不允许您将bash
与索引阵列名称(4.2或更早版本)一起使用的-v
版本,您可以后退以检查扩展是否未设置。
if [[ "${Redone[$i]+x}" = x ]]
由于您使用空字符串作为每个字符串的值,因此${Redone[$i]+x}
仅在x
是数组中的键时才会扩展为$i
。
答案 2 :(得分:0)
正则表达式匹配会导致部分匹配,我更喜欢一种更具体的解决方案。
NStep=25
NTotal=435
Redone=('375' '400' '425' 'last')
for i in $(seq 0 $NStep $NTotal)
do
isPresent=0
for redone in "${Redone[@]}"
do
if [ "${redone}" = "${i}" ]
then
isPresent=1
break
fi
done
if [[ "${isPresent}" -eq "1" ]]; then
echo "do something"
else
echo "do something else"
fi
done
答案 3 :(得分:0)
有很多方法可以检查数组中是否包含元素:
NStep=25
NTotal=435
Redone=('375' '400' '425' 'last')
for i in $(seq 0 $NStep $NTotal)
do
if printf "%s\0" "${Redone[@]}" | grep -F -x -q -z "$i"; then
# or if printf "%s\n" "${Redone[@]}" | grep -F -x -q "$i";
echo "do something"
else
echo "do something else"
fi
done
但是我认为只过滤不感兴趣的元素会更简单:
comm -12 <(printf "%s\n" "${Redone[@]}" | sort) <(seq 0 "$NStep" "$NTotal" | sort)
# outputs 375 400 425
或者您可以使用join
并为seq
中的行编号,然后重新排序并进行一些替换:
# this will print 15 lines of 'do something else'
# and 3 lines with 'do something'
# exactly the same as the `for i in ...` loop above
join -22 -a2 -e "do something else" -o2.1,1.1 <(printf "%s\n" "${Redone[@]}" | sort) <(seq 0 $NStep $NTotal | nl -w1 | sort -k2) |
sort -n -k1 |
cut -d' ' -f2- |
sed 's/[0-9]\+/do something/'