bash Shell UNIX:grep 通配符

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21492833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 09:25:35  来源:igfitidea点击:

Shell UNIX : grep wild card

bashshellunixgrepwildcard

提问by Arthur Sigma

I can't figure out why the wild character * is interpreted differently in the following examples with grep :

我无法弄清楚为什么在以下带有 grep 的示例中对通配符 * 的解释不同:

find . -type f -name \*

Results :

结果 :

./tgt/etc/test_file.c
./tgt/etc/speleo/test_file.c
./tgt/etc/other_file.c
./src/file.c

I want to return from this command the files that match a pattern with eventually a wildcard *. But :

我想从这个命令返回匹配模式的文件,最终是一个通配符 *。但 :

find . -type f -name \* | grep "tgt/etc/*" # this one works
find . -type f -name \* | grep tgt/etc/* # not this one
find . -type f -name \* | grep tgt/et*/s* # this one works
find . -type f -name \* | grep "tgt/et*/s*" # not this one

I'd like to have an implementation which works fine with both cases. What should I use ?

我想要一个在这两种情况下都能正常工作的实现。我应该用什么?

回答by Barmar

The first argument to grepis not a wildcard, it's a regular expression. In a regular expression, *means to match any number of the character or expression that precedes it. So

的第一个参数grep不是通配符,它​​是一个正则表达式。在正则表达式中,*表示匹配任意数量的字符或前面的表达式。所以

grep "tgt/etc/*"

means to match tgt/etcfollowed by zero or more /characters. In a wildcard, *means to match any number of any characters, the equivalent regular expression is .*. For your purposes, the commands you want are:

表示匹配tgt/etc后跟零个或多个/字符。在通配符中,*表示匹配任意数量的任意字符,等效的正则表达式为.*. 出于您的目的,您需要的命令是:

find . -type f -name \* | grep "tgt/etc/"
find . -type f -name \* | grep "tgt/et.*/s"

Also, if you don't quote the argument, and it contains any *characters, the shell will expand the argument as a filename wildcard before passing them as arguments to grep. So when you write:

此外,如果您不引用参数,并且它包含任何*字符,shell 将在将参数作为参数传递给grep. 所以当你写:

find . -type f -name \* | grep tgt/etc/*

the shell will expand this to

外壳会将其扩展为

find . -type f -name \* | grep tgt/etc/file1 tgt/etc/file2 tgt/etc/file3

This will treat the tgt/etc/file1as the regular expression to search for, and look for it inside the remaining files -- it will notprocess the input from the pipeline because it was given filename arguments.

这会将 视为tgt/etc/file1要搜索的正则表达式,并在其余文件中查找它——它不会处理来自管道的输入,因为它被赋予了文件名参数。

回答by Christopher Creutzig

The unquoted examples (without the ") are expanded by the shell, before grepever sees them. That is just the way Unix shells work.

未引用的示例(没有")在grep看到它们之前由外壳展开。这就是 Unix shell 的工作方式。

For the quoted ones, note that *in a grep pattern means something different from what it means to the shell and to find: It means “repeat the preceding character any number of times (including zero).”

对于引用的那些,请注意*在 grep 模式中的含义不同于它对 shell 和 to 的find含义:它的意思是“重复前面的字符任意次数(包括零)”。

回答by zmo

it's because grepuses regexps and no wildcards.

这是因为grep使用正则表达式而没有通配符。

so basically, what you do is:

所以基本上,你要做的是:

  • tgt/etc/*checking zero or sereval /
  • tgt/et*/s*checking zero or several tand zero or several s
  • tgt/etc/*检查零或sereval /
  • tgt/et*/s*检查零个或多个t和零个或多个s

but thing is that when you do not put quotes around the regexp, the shell is expanding the *as wildcards, which messes up the regexp grep sees.

但问题是,当您不在正则表达式周围加上引号时,shell 会将*通配符扩展为通配符,这会弄乱 grep 看到的正则表达式。