1

是否有任何 bash 命令可以执行类似以下操作:

if [[ $string =~ $pattern ]]

但它适用于简单的通配符 (?,*) 而不是复杂的正则表达式 ??


更多信息:

我有一个配置文件(一种类似 .ini 的文件),其中每一行都由通配符模式和其他一些数据组成。
对于我的脚本接收到的任何给定输入字符串,我必须在配置文件中找到通配符模式与输入字符串匹配的第一行,然后返回该行中的其余数据。
这很简单。我只需要一种将字符串与通配符模式而不是正则表达式匹配的方法,因为模式可能包含点、括号、破折号等,我不希望这些被解释为特殊字符。

4

3 回答 3

3

这个[ -z ${string/$pattern} ]技巧有一些非常严重的问题:如果字符串为空,它将匹配所有可能的模式;如果它包含空格,则测试命令会将其解析为表达式的一部分(尝试string="x -o 1 -eq 1"娱乐)。bash 的 [[ 表达式与 == 运算符进行原生通配符匹配,因此不需要所有这些复杂(且容易出现问题)的技巧。只需使用:

if [[ $string == $pattern ]]
于 2009-12-23T18:26:24.983 回答
2

有几种方法可以做到这一点。

在 bash >= 3 中,你有你描述的正则表达式匹配,例如

$ foo=foobar
$ if [[ $foo =~ f.ob.r ]]; then echo "ok"; fi
   ok

请注意,此语法使用正则表达式模式,因此它使用.而不是?匹配单个字符。

如果您想要做的只是测试字符串是否包含子字符串,那么还有更经典的方法可以做到这一点,例如

# ${foo/b?r/} replaces "b?r" with the empty string in $foo
# So we're testing if $foo does not contain "b?r" one time
$ if [[ ${foo/b?r/} = $foo ]]; then echo "ok"; fi

您还可以通过以下方式测试字符串是否以表达式开头或结尾:

# ${foo%b?r} removes "bar" in the end of $foo
# So we're testing if $foo does not end with "b?r"
$ if [[ ${foo%b?r} = $foo ]]; then echo "ok"; fi

# ${foo#b?r} removes "b?r" in the beginning of $foo
# So we're testing if $foo does not begin with "b?r"
$ if [[ ${foo#b?r} = $foo ]]; then echo "ok"; fi
     ok

有关这些语法的更多信息,请参阅man bash的参数扩展段落。分别使用or代替and将实现最长匹配而不是简单匹配。##%%#%

处理通配符的另一种非常经典的方法是用例:

case $foo in 
   *bar)
       echo "Foo matches *bar"
       ;;
   bar?)
       echo "Foo matches bar?"
       ;;
   *)
       echo "Foo didn't match any known rule"
       ;;
esac
于 2009-12-23T08:53:20.163 回答
0

约翰 T 的回答被删除了,但我实际上认为他是在正确的轨道上。这里是:

另一种适用于大多数 bash 版本的可移植方法是回显您的字符串,然后通过管道传输到 grep。如果未找到匹配项,它将评估为 false,因为结果将为空白。如果返回某些内容,它将评估为 true。

[john@awesome]$string="Hello World"
[john@awesome]$if [[ `echo $string | grep Hello` ]];then echo "match";fi
match

约翰没有考虑答案所要求的通配符。为此,请使用、egrepaka使用正则表达式通配符。这里,是通配符,是一个乘数,意思是“任意数量的这些”。所以,约翰的例子变成了:grep -E.*.*

$ string="Hello World"
$ if [[ `echo $string | egrep "Hel.*"` ]]; then echo "match"; fi

通配符表示法是相当标准的.正则表达式,因此它应该适用于任何使用正则表达式的命令。

如果您需要转义特殊字符,它确实会变得讨厌,所以这可能不是最佳的:

$ if [[ `echo $string | egrep "\.\-\$.*"` ]]; then echo "match"; fi
于 2009-12-23T09:10:51.230 回答