我有一个充满应用程序源文件的文件夹,该项目使用 git 进行版本控制,因此有一个.git
目录:
├── composer.json
├── .git
│ ├── branches
│ ├── config
│ ├── info
│ ├── logs
│ ├── objects
│ ├── packed-refs
│ └── refs
├── .gitignore
├── Gruntfile.js
├── less
│ ├── framework
│ ├── index.less
│ └── view_specific.less
├── package.json
[...]
我经常需要对所有源文件执行某些操作,同时忽略版本控制文件,即.git
目录及其下的所有内容。
我通常使用-not -path
选项来find
排除目录,例如
find . -not -path "*git*"
这样做的问题是它太宽泛了,例如它将排除该.gitignore
文件以及任何其他包含该文件的文件git其中,例如激荡,逃亡者
我发现find
and-name
开关似乎-prune
确实针对.git
目录及其内容:
% find . -name ".git" -prune -o -print | grep git
./.gitignore
但我不明白如何-name
匹配文件名。
从man find
-name pattern Base of file name (the path with the leading directories removed) matches shell pattern pattern.
对我来说,这意味着,-name
仅当模式与文件名中的最后一段匹配时才匹配,例如-name foo
会匹配/dir1/dir2/foo
但不是 /dir1/dir2/foo/dir3/dir4/some_file
对我来说,重点-path
是匹配模式,例如foo
与具有路径名的文件,例如/dir1/dir2/foo/dir3/dir4/some_file
.
它似乎-name
可以匹配文件路径中的任何段 - 不仅仅是最后一个段 - 只要它与斜杠内的段完全匹配?
否则如何-name
匹配文件名?
答案1
要忽略.git
目录及其下面的所有内容,您需要这样的构造
find . \( -name '.git' -prune \) -o \( -print {or whatever else you want to do} \)
这表明当它找到一个名为它的find
文件或目录时.git
修剪它的树,而不是沿着那条路进一步下降。其他一切都可以在另一半的范围内进行匹配和处理或者条件构造。
(括号上的反斜杠阻止 shell 处理它们,对于这个简单的示例在技术上是不必要的。我将它们留在里面是为了明确地表明和和或者构造绑定。)
现在,考虑一下您对名为 的文件夹的担忧foo
:
例如
-name foo
会匹配/dir1/dir2/foo
但不匹配/dir1/dir2/foo/dir3/dir4/some_file
你是对的,但我认为你错过了推论。到了某个时候find
就会达到/dir1/dir2/foo
。 will-name foo
匹配,因此-prune
will 被调用。如果不先看到它自己find
,就无法到达下面。foo
foo
因此/dir1/dir2/foo/dir3/dir4/some_file
永远无法达到。
检查的初始结果是在某种程度上-name foo
匹配/dir1/dir2/foo/dir3/dir4/some_file
,但实际上它匹配/dir1/dir2/foo
并且放弃了对该树的任何进一步检查。
与仅作为路径的最后一个组成部分-name foo
匹配的相比,仅当是完整路径时才会匹配。 (可能会在顶层匹配 a ,但永远无法匹配。)foo
-path foo
foo
find * -path foo
foo
find . -path foo
./foo
答案2
你的理解-name
是正确的。它只匹配文件名;通向该文件的路径(包含目录的链)是无关紧要的。
你缺少的是 的效果-prune
。对比
find . -name ".git" -o -print
这意味着“如果它被调用.git
,那么什么都不做,否则打印路径并递归到它(如果它是一个目录)”
find . -name ".git" -prune -o -print
这意味着“如果它被称为.git
,那么不要递归它,否则打印路径并递归到它(如果它是目录)”。