Linux命令进行通配符匹配

发布于 2024-08-15 08:06:32 字数 357 浏览 2 评论 0原文

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

if [[ $string =~ $pattern ]]

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


更多信息

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

Is there any bash command to do something similar to:

if [[ $string =~ $pattern ]]

but that it works with simple wild cards (?,*) and not complex regular expressions ??


More info:

I have a config file (a sort of .ini-like file) where each line is composed of a wild card pattern and some other data.
For any given input string that my script receives, I have to find the first line in the config file where the wild card pattern matches the input string and then return the rest of the data in that line.
It's simple. I just need a way to match a string against wild card patterns and not RegExps since the patterns may contain dots, brackets, dashes, etc. and I don't want those to be interpreted as special characters.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

人生戏 2024-08-22 08:06:32

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

if [[ $string == $pattern ]]

The [ -z ${string/$pattern} ] trick has some pretty serious problems: if string is blank, it'll match all possible patterns; if it contains spaces, the test command will parse it as part of an expression (try string="x -o 1 -eq 1" for amusement). bash's [[ expressions do glob-style wildcard matching natively with the == operator, so there's no need for all these elaborate (and trouble-prone) tricks. Just use:

if [[ $string == $pattern ]]
凉月流沐 2024-08-22 08:06:32

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

在 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

There's several ways of doing this.

In bash >= 3, you have regex matching like you describe, e.g.

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

Note that this syntax uses regex patterns, so it uses . instead of ? to match a single character.

If what you want to do is just test that the string contains a substring, there's more classic ways of doing that, e.g.

# ${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

You can also test if a string begins or ends with an expression this way:

# ${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

See the Parameter Expansion paragraph of man bash for more info on these syntaxes. Using ## or %% instead of # and % respectively will achieve a longest matching instead of a simple matching.

Another very classic way of dealing with wildcards is to use case:

case $foo in 
   *bar)
       echo "Foo matches *bar"
       ;;
   bar?)
       echo "Foo matches bar?"
       ;;
   *)
       echo "Foo didn't match any known rule"
       ;;
esac
败给现实 2024-08-22 08:06:32

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

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

[john@awesome]$string="Hello World"
[约翰@awesome]$if [[ `echo $string | grep Hello`]];然后回显“匹配”;fi
匹配

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

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

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

如果您需要转义特殊字符,它确实会变得令人讨厌,因此这可能不是最佳选择:

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

John T's answer was deleted, but I actually think he was on the right track. Here it is:

Another portable method which will work in most versions of bash is
to echo your string then pipe to grep. If no match is found, it will
evaluate to false as the result will be blank. If something is returned,
it will evaluate to true.

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

What John didn't consider is the wildcard requested by the answer. For that, use egrep, a.k.a. grep -E, and use the regex wildcard .*. Here, . is the wildcard, and * is a multiplier meaning "any number of these". So, John's example becomes:

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

The . wildcard notation is fairly standard regex, so it should work with any command that speaks regex's.

It does get nasty if you need to escape the special characters, so this may be sub-optimal:

$ if [[ `echo $string | egrep "\.\-\$.*"` ]]; then echo "match"; fi
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文