我有名为lect1.txt
、lect2.doc
和 的文件lect3.doc
。
我想获取一个文件,该文件是一个.txt
文件,并且包含lect
作为文件名。
我试过
find *.txt | grep lect*
它什么也没返回。
但当我这样做的时候
find *.txt | grep "lect*"
它回来了lect1.txt
。
这两种表达方式有什么区别?
答案1
grep
在命令行传递的文件中搜索第一个参数(模式)或者 stdin
如果没有文件通过。
如果没有引号,您的 shell 将扩展lect*
到目录中以lect
.您的命令将是:
grep lect1.txt lect2.doc lect3.doc
意思是lect1.txt
搜索两个.doc
文件中的文本。除非其中一个文件中.doc
包含该短语,否则它不会返回任何内容。lect1.txt
更准确地说,它将查找lect1
后跟任何字符(.
) 后跟txt
,因此它也会查找lect1-txt
等lect1xtxt
)
在第二个示例中,您引用了引号"lect.*"
,以便外壳程序不会扩展它,并将其按原样传递到grep
.仅将模式作为参数传递,grep
将搜索传入的文件名stdin
以查找模式,我相信这就是您所追求的。
答案2
find *.txt | grep lect*
您通常希望提供路径名作为 的第一个参数find(1)
,而不是文件名。它当然不是文件名模式。 shell在调用之前会扩展为当前目录中*.txt
所有文件的名称,这不是您想要的。*.txt
find
该命令更有用的变体是
find . -name 'lect*' | grep 'txt$'
或者
find . -name 'lect*txt'
另外,请注意find(1)
使用全局表达式在-name
初选中,而grep(1)
使用常用表达。这在这里很重要,因为这*
在两个系统中意味着有些不同。
BSD 和 GNU 实现find
具有非标准的-regex
主要实现,它允许您使用正则表达式:
find . -regex '.*/lect.*txt'
请注意,该模式必须与所有的找到的路径find
,这就是我们需要前缀的原因.*/
,并且不需要像使用 一样将 固定txt
到末尾。$
grep
答案3
你误用了find
,它意外地起作用了。你会看到 - 通过运行:
find *.txt
你是什么实际上正在做的是调用:
find lect1.txt
而你所取得的成就只不过是echo
。但是,如果您使用搜索条件运行 find - 例如:
find . -name '*.txt'
然后它将遍历当前目录.
并打印任何子目录中与规范匹配的任何文件名。
但应该小心,因为 find 解释的 '*'、*
shell 中的 和*
正则正则表达式中的 含义不同。
如果您的grep
ing*
表示“前一个字符的零个或多个实例”。
所以你实际上是:
- 回显所有文件名(globbing
*.txt
)。 - grepping 打印任何与中间带有
lec
、lect
、lectt
等的任何字符匹配的内容。lecttttttt
但在你的第一个例子中,你 grep 甚至没有走那么远 -壳正在扩展您的模式,因此它实际上正在查找任何匹配的内容echo lect*
- 这可能会意外工作,因为您的目录中有一个文件可以适当扩展,但它没有执行您想要的操作。
我建议你想要的是:
find . -name 'lect*.txt' -print