重击“如果数组中的数字”还考虑部分匹配。如何解决呢?

时间:2020-02-10 09:30:44

标签: bash

我写了以下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

但是,对于步骤02575,它会输入if语句(并执行某些操作),而我希望它输入else语句(并做其他事情)。如何使我的正则表达式更具体或重写if语句?

谢谢

4 个答案:

答案 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/'