我试图列出我的主目录中的一些隐藏文件,并且grep
在与命令结合时遇到了非常奇怪的命令行为ls
。
- 我
ls -a
在我的主目录上执行并按预期获取了所有文件,包括隐藏文件。 - 我想列出所有隐藏文件从“xau”开始,所以我执行了
ls -a |grep -i .xau*
并且它也按预期工作。 - 然后我
ls -a |grep -i .x*
在同一目录中执行但是它根本没有列出任何内容。 - 然后我错误地输入了
ls -a |grep -i .*x
(请注意,这次通配符 * 和字符 'x' 交换了位置)有趣的是,它的表现与我在步骤 3 中的预期一致。我用这个命令尝试了同样的事情ls -a .*x
,ls -a .*X
但我得到了没有这样的文件或目录错误。
我已经添加了实际的文本输出这里。
你们中的一些人可能会问为什么不直接使用,ls -a .x*
但grep
它可以打印出适当的颜色。那么有人可以向我解释一下吗?
答案1
你正在遭受过早的全球扩张。
.xa*
不会展开,因为它与当前目录中的任何内容都不匹配。 (Glob 区分大小写。)但是,.x*
做匹配某些文件,因此 shell 在grep
看到它之前会对其进行扩展。
当grep
接收多个参数时,它假定第一个参数是模式,其余参数是用于搜索该模式的文件。
因此,在命令 中ls -a | grep -i .x*
, 的输出ls
是被忽略,并在文件“.xsession-errors.old”中搜索模式“.xsession-errors”。毫不奇怪,什么也没发现。
为了防止这种情况,请将特殊字符放在单引号或双引号内。例如:
ls -a | grep -i '.x*'
你也正遭受着正则表达式与 glob 的混淆。
您似乎正在寻找以文字字符串“.x”开头且后跟任何内容的文件,但正则表达式的工作方式与文件通配符不同。这*
在正则表达式中表示“前面的字符零次或多次”,而不是像文件 glob 中那样的“任何字符序列”。那你又怎样大概想要的是:
ls -a | grep -i '^\.x'
这会搜索其名称的文件开始带有文字字符“.x”或“.X”。实际上,由于您只指定一个字母,因此您可以轻松地使用字符类而不是-i
:
ls -a | grep '^\.[xX]'
重点是正则表达式与文件 glob 有很大不同。
如果您ls -a | grep -i '.x*'
按照建议尝试,您会非常惊讶地发现每个文件都会显示! (与直接输出相同ls -a
,只是像 中那样放在单独的行上ls -a -1
。)
怎么会?
嗯,在正则表达式(但不是在 shell glob 中),句点 ( .
) 表示“任何单个字符”。星号 ( *
) 表示“零个或多个前面的字符”。因此,正则表达式的.x*
意思是“任何字符,后跟零个或多个字符‘x’的实例”。
当然,你不允许有空文件名,所以每一个文件名包含“一个字符后跟至少零个‘x’”。 :)
概括:
为了获得您想要的结果,您需要了解两件事:
- 不带引号的特殊全局字符(包括
*
、?
和[]
其他一些字符)将被扩展通过外壳在您运行的命令之前看到他们与 - 正则表达式与文件 glob 不同(并且更强大)。
答案2
问题是您没有*
用引号引起来并让 shell 在运行命令之前展开它。看:
$ touch .xau1 .xau2
# this won't work
$ ls -a | grep -i .xau*
# but this does
$ ls -a | grep -i ".xau*"
.xau1
.xau2
# this one too
$ ls -a | grep -i '.xau*'
.xau1
.xau2
# check what shell sees
$ ls -a | grep -i .xau* # now don't press enter but C-x * and you'll see this:
$ ls -a | grep -i .xau1 .xau2