最近,我与一位同事交谈时,他正处于自我封闭状态,这时我发现他做了类似的事情ls -l | grep asdf*
。
我问他:“为什么弄得一团糟?”他回答说:“我一向都是这么做的。”
我并没有立即发现任何问题,但仍然感觉不对劲。当我后来亲自尝试时,我看到了不同的行为:
--> ls -l | grep ls
-rwxr-xr-x 1 root root 22896 Nov 19 2012 false
-rwxr-xr-x 1 root root 105840 Nov 19 2012 ls
-rwxr-xr-x 1 root root 44640 Nov 19 2012 lsblk
-rwxr-xr-x 1 root root 6272 Nov 19 2012 lsmod
-rwxr-xr-x 1 root root 31912 Nov 19 2012 ntfsls
--> ls -l | grep ls*
Binary file lsblk matches
Binary file lsmod matches
这里到底发生了什么?我认为最糟糕的情况是,grep 会将其视为正则表达式l(s*)
并返回所有出现的l
,但这个输入甚至没有出现在 ls 中!(我从 运行它/bin
)。
当您在搜索字符串后添加一个 glob 时,grep 会做什么?我是否应该告诉我的同事以后不要再这样做?
答案1
当你这样做时grep ls*
,壳首先扩展ls*
为当前目录中匹配的文件列表,因此命令变为
ls -l | grep ls lsblk lsmod
在这种情况下,grep
将忽略标准输入并将第一个参数ls
视为要匹配的模式里面文件lsblk
和lsmod
,就像您输入的那样grep ls lsblk lsmod
(大概在/bin
):
$ grep ls lsblk lsmod
Binary file lsblk matches
Binary file lsmod matches
另一方面,如果当前目录中没有 glob 匹配,并且nullglob
未设置 shell 的选项,ls*
则将保留联合国展开,以便grep
查看ls*
并匹配任何文件名称匹配l
后跟零个或多个s
字符(基本上是任何带有 的文件名l
)例如:
$ pwd
/home/steeldriver
$ echo ls*
ls*
ls*
(我的主目录中没有与 shell glob 匹配的文件);然后
$ ls /bin | grep 'ls*'
bzless
chacl
false
.
.
.
zless
不要这么做
答案2
为了更加安全,您的同事应该使用:
ls -l | grep "asdf*"
处理管道输出,使用引号我们跳过 shell 文件扩展,所以我们说查找后跟asd
零个或多个 的行f
,更好的用例是:
ls -l | grep "asdf.*"
另一件需要提及的事情是,如果当前目录中没有任何文件与该模式匹配,它将被视为原样grep
,大多数情况下都是如此。
另请注意,解析ls
输出是这不是一件好事。