测试字符串是否包含子字符串


40

我有代码

file="JetConst_reco_allconst_4j2t.png"
if [[ $file == *_gen_* ]];
then
    echo "True"
else
    echo "False"
fi

我测试是否file包含“ gen”。输出为“ False”。真好!

问题是当我用变量替换“ gen”时testseq

file="JetConst_reco_allconst_4j2t.png"
testseq="gen"
if [[ $file == *_$testseq_* ]];
then
    echo "True"
else
    echo "False"
fi

现在输出为“ True”。怎么会这样?如何解决问题?


Answers:


25

您需要$testseq使用以下方式之一对变量进行插值:

  • $file == *_"$testseq"_*(此处$testseq视为固定字符串)

  • $file == *_${testseq}_*(此处$testseq被视为模式)。

_紧随其后的变量名称将被视为变量名称的一部分(这是变量名称中的有效字符)。


正确答案,因为它适用于OP,但没有便携性。(这不是对所提供答案的批评,只是对读者的警告)。;-)
Cbhihe

28

使用=~运算符进行正则表达式比较:

#!/bin/bash
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"
if [[ $file =~ $testseq ]];
then
    echo "True"
else
    echo "False"
fi

这样,它将比较其内容是否$file存在$testseq

user@host:~$ ./string.sh
False

如果我改变testseq="Const"

user@host:~$ ./string.sh
True

但是,要小心喂食$testseq。如果字符串以某种方式表示正则表达式([0-9]例如),则有更多机会触发“匹配”。

参考


20
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"

case "$file" in
    *_"$testseq"_*) echo 'True'  ;;
    *)              echo 'False'
esac

使用case ... esac是以便携式方式执行模式匹配的最简单方法之一。它的工作原理是在其他语言中“开关”的声明(bashzsh,并且ksh93还允许你做落空各种不兼容的方式)。所使用的模式是标准文件名遍历模式。

您遇到的问题是由于_变量名中的有效字符。因此,外壳将显示*_$testseq_*为“,*_后跟变量的值$testseq_*”。该变量$testseq_是未定义的,因此将其扩展为空字符串,最后得到*_*,显然与$file您拥有的值匹配。True只要文件名中$file至少包含一个下划线,您就可以期望得到。

要正确定界变量的名称,请"..."在扩展名周围使用*_"$testseq"_*。这将使用变量的值作为字符串。您是否要将变量的值用作模式,请*_${testseq}_*改用。

另一个快速解决方案是在值中包含下划线$testseq

testseq="_gen_"

然后仅用*"$testseq"*作模式(用于字符串比较)。


因此,shell将寻找变量$ testseq_而不是找到它,而是用一个空字符串代替它。
Viesturs

@Viesturs这是问题的核心,是的。
库桑兰达

1
对于字符串搜索应该是*"$testseq"*case[[...]](除了zsh的,除非你能globsubst)
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.