为什么有时发现匹配其命令行路径参数?


9

在Linux上,

cd /tmp
mkdir foo; cd foo

现在,跑步

find . -name 'foo'

没有输出。而跑步

find /tmp/foo -name 'foo'

提供/tmp/foo对我来说没有意义的输出。有人可以解释为什么吗?


2
在给定的路径内找到符合要求的搜索。因此,如果您输入的./内容不匹配foo
Costas

@Costas:我明白。我不明白的是,如果给我绝对的路径,为什么它会有所作为find
约克

@York在某些情况下,没有永远都是正确的行为。想象一下一个符号链接,其名称bar指向foo搜索路径之外的文件。可以匹配吗?
Hauke Laging

1
./tmp/foo是不一样的-它们是两个不同的硬链接到同一个目录下; find /tmp/foo/. -name 'foo'也没有找到任何东西。
jimmij

@jimmij:运行时find /tmp/foo -name 'foo',我要求bash在目录中找到/tmp/foo一个名为“ foo”的文件。因为目录/tmp/foo为空,所以它应该什么也不返回。我不明白为什么它会回来/tmp/foo。另一方面,当我运行时find . -name 'foo',我在问bash相同的事情,即在当前目录(恰好是/tmp/foo)中找到一个文件,其名称为“ foo”,并且不返回任何有意义的文件。
约克

Answers:


15

find遍历指定的目录树,并为找到的每个文件评估给定的表达式。遍历从给定路径开始。以下是操作方式的摘要find . -name foo

  • 命令行上的第一个路径: .
    • 基本名称(.)是否与模式匹配foo?不,什么都不做。
      碰巧这/tmp/foo是同一目录的另一个名称。但是find不知道(并且不应该尝试找出答案)。
    • 路径是目录吗?是的,所以遍历它。枚举中的条目.,并对每个条目执行遍历过程。
      • 该目录为空:除了.和以外..,它find不包含任何条目,该条目不会递归遍历。这样工作就完成了。

find /tmp/foo

  • 命令行上的第一个路径: /tmp/foo
    • 基本名称(foo)是否与模式匹配foo?是的,因此条件匹配。
      • 没有与此条件相关联的操作,因此请执行默认操作,即打印路径。
    • 路径是目录吗?是的,所以遍历它。枚举中的条目/tmp/foo,并对每个条目执行遍历过程。
      • 该目录为空:除了.和以外..,它find不包含任何条目,该条目不会递归遍历。这样工作就完成了。

碰巧的是./tmp/foo它们具有相同的目录,但这不足以保证find两者都具有相同的行为。该find命令提供了区分同一文件路径的方法。该-name谓词是其中之一。find /tmp/foo -name foo匹配起始目录及其下的任何文件foofind . -name .仅匹配起始目录(.在递归遍历期间永远找不到)。


“除了。和..以外,它不包含任何条目,这些条目不会递归遍历。” 我假设“不横向递归”是指“ ..”。如果这是正确的,那么在“ ..”上下文中“递归横向”是什么意思?
Faheem Mitha

@FaheemMitha“不递归遍历”适用于...。(如果以递归方式find遍历.,它将最终一次又一次地遍历该目录,并…).并且..不只是特殊的符号,它们还显示为目录条目。
吉尔(Gilles)'所以

5

在应用测试之前,没有对命令行参数进行规范化。因此,结果因所使用的路径而异(如果涉及符号链接):

cd /tmp
mkdir foo
ln -s foo bar
find /tmp/foo -name foo
find /tmp/bar -name foo

在“您的情况”中,两个调用都将给出相同的结果,这可能会(更加)令人困惑。-mindepth 1如果您希望忽略起点,则可以使用(可以是非POSIX)。


-mindepth 1作品。但是,我仍然不明白为什么,find . -name 'foo'并且find /tmp/foo -name 'foo'行为有所不同。
2016年

2

(gnu)find显示在提供给命令的路径中找到的所有匹配项,因为它开始与命令行参数进行比较,并从此处更深地进入目录结构(因此,-maxdepth 0将测试限制在基本级别或仅命令行参数中,而-mindepth 1按照man find说明跳过命令行参数)。这就是find /tmp/foo -name 'foo'即使目录本身为空也要产生一个匹配项的原因。

find . -name 'foo'另一方面,不会产生任何结果,因为.(dot)是一个特殊文件,其作用类似于与相同inode的硬链接/tmp/foo-它像一个单独的(尽管是特殊的)文件名,而不是符号链接或表达式,路径名由外壳扩展。因此,在给定示例中,find应用于命令行参数的第一个测试将不会显示任何匹配项,因为.实际上与中定义的名称模式不匹配-name 'foo'。也不对/tmp/foo/.,因为一个测试-name是在路径只(见的基名执行模式man find),在这里又是.

尽管从用户的角度看这种行为可能不是预期的或看起来很直观(是的,它也让我一开始很困惑),但它并不构成错误,而是与手册页和信息页中描述的逻辑和功能相对应的( gnu)找到。


0

我曾尝试评论吉尔斯的答案,但时间太长,无法发表评论。因此,我将其作为我自己问题的答案。

吉尔斯的解释(还有舍维克的解释)很明确而且很有意义。这里的关键点是,不仅find尝试(递归地)匹配给定路径内文件的文件名,而且还尝试匹配给定路径本身的基本名。

另一方面,是否有任何证据证明这是find应该起作用的方式,而不是错误?我认为,最好不要使结果不一致,find .并且find ABSOLUTE-PATH因为不一致总是令人困惑,并且可能浪费开发人员大量时间来试图找出“问题所在”。就我而言,我正在编写脚本,并且路径是从变量中获取的。因此,为了使我的脚本正常工作,我想做的就是编写find $path/. -name 'pattern'

最后,我认为find可以通过.在继续操作之前始终将其替换为当前目录来获得一致的结果。


-1

foo开始相对搜索的目录中没有命名的对象。

如果使用绝对名称作为起始目录gfind时报告该错误,那您是正确的/tmp/foo

Gfind与标准有各种差异,似乎您找到了另一个。当您需要更符合标准的解决方案时,建议将sfind其作为的一部分schilytools

-name适用于目录搜索结果。您提到的两种情况都不会fooreaddir()操作返回目录条目。


我怀疑这也是一个错误。以下是以下内容的输出find --version:find(GNU findutils)4.4.2版权所有(C)2007自由软件基金会,公司。许可证GPLv3 +:GNU GPL版本3或更高版本< gnu.org/licenses/gpl.html >
York

好吧,我用find(POSIX认证) gfind和来检查您的示例命令sfind。该问题仅在您使用时存在gfind。在Linux上,gfind不是以本机名称安装的,而是以的名称安装的find
2016年

3
find /tmp/foo -name foo输出正确/tmp/foo。(Cc @York)这是OpenBSD find,GNU find,BusyBox find,Solaris find和任何其他POSIX兼容的行为find(“如果所检查的文件名的基本名称与模式(…)相匹配,则主数据库的评估结果为true ”。是作为路径操作数传递的,不readdir涉及任何调用)。
吉尔斯(Gillles)“所以-别再邪恶了”
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.