【问题标题】:Linux command to do wild card matchingLinux命令进行通配符匹配
【发布时间】:2009-12-23 08:35:38
【问题描述】:

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

if [[ $string =~ $pattern ]]

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


更多信息:

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

【问题讨论】:

  • 您到底想完成什么?更多细节请...
  • 将字符串与通配符模式匹配
  • 人力资源管理。很公平。如果这是一个“我如何使用 unix 工具做到这一点”的问题,我的答案是“perl”。如果它是“我如何用 bash 做到这一点”,我说它应该作为 bash 编程问题迁移到 stackoverflow.com。有什么想法吗?
  • 因为我要求的是一个简单的命令,我并不认为这是一个真正的“编程”问题
  • 好吧,既然您真正要问的是 bash 语法,也就是 bash 编程语法,我认为这更像是一个编程问题。我正在投票迁移。这是一个很好的问题,但我认为更适合 SO。

标签: linux bash shell wildcard


【解决方案1】:

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

if [[ $string == $pattern ]]

【讨论】:

  • 确定是两个等号?
  • 是的,对于[[ $foo == $bar ]]bashfoo 的内容与bar 中的模式相匹配。请注意,这与[[ $foo == "$bar" ]] 相同,不会将bar 的内容视为模式。
  • @GetFree:两个等号似乎是首选,但在这种特殊情况下,您可以交替使用===
  • @Chris Johnsen:实际上比这更酷,因为您可以混合引用(文字)和未引用(模式匹配)字符串,例如 [[ $string == "$foo"$bar ]] 将要求 $foo 部分匹配确切地说,$bar 部分必须作为模式匹配。
【解决方案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参数扩展 段落。分别使用##%% 代替#% 将实现最长匹配而不是简单匹配。

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

case $foo in 
   *bar)
       echo "Foo matches *bar"
       ;;
   bar?)
       echo "Foo matches bar?"
       ;;
   *)
       echo "Foo didn't match any known rule"
       ;;
esac

【讨论】:

  • 啊,这确实是另一种选择 :-)
【解决方案3】:

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

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

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

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

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

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

如果您需要转义特殊字符,这确实很麻烦,所以这可能不是最佳选择:

$ if [[ `echo $string | egrep "\.\-\$.*"` ]]; then echo "match"; fi

【讨论】:

  • 是的,不会打扰。但是感谢您恢复我的回答,我猜! :)
  • 你删除了它,因为我正在制作这个建议作为评论......它确实分解为“使用正则表达式通配符”的建议,但是哦,好吧。不是一个很好的答案,只是一个答案。
  • 肯定会的。 "?" 通配符的意思是“匹配一个字符,无所谓”。这正是"." 在正则表达式中的含义。它不是通配符的同一个字符,但具有相同的含义。
  • GetFree: '?'通配符将替换为“。”就像使用 '=~' 时一样。
  • 所以在正则表达式中,".""?" 通配符相同; ".+" 表示“匹配一个或多个任意字符”; ".*" 表示“匹配零个或多个任意字符”。 foo. 匹配 "foob" 但不匹配 "foobar"; foo.+ 匹配 "foob" 和 "foobar" 但不匹配 "foo"; foo.* 匹配所有 3 个。
猜你喜欢
  • 2017-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多