我尝试使用 find 命令递归搜索目录树并返回与给定名称匹配的目录的所有结果。
find . -type d -name '<NAME>'
我得到返回的路径列表,这些路径被打印到日志文件中。我希望能够忽略父目录中包含名为 omit.txt 的文件的任何结果。
./parent_directory/ 名称>
我一直在尝试用以下方法做到这一点
find . -type d -name '<NAME>' \( ! -wholename "*omit.txt*" -prune \)
我正在尝试使用 prune 命令来忽略包含该文件的结果,但我认为这可能只适用于目录。任何帮助将不胜感激。我试图仅用一个命令来完成此操作并尽可能维护输出文件 -
答案1
我认为您不能在 内完全执行此操作find
,因为您需要在处理目录时能够看到目录内的文件。-prune
必须对目录本身进行操作,但-path
其他条件只能看到find
已经下降到目录后的文件名。
我能想到的就是分出一个 shell 来查看目录内部。像这样的东西:
$ mkdir -p x y/z ; touch x/foo y/omit.txt
$ find -type d \( -exec sh -c '[ -e "$1/omit.txt" ]' sh {} \; -prune -o -print \)
.
./x
foo -o bar
不评估bar
是否foo
成功,因此如果目录被修剪,则打印不会运行。添加-o -print
到末尾也可以打印目录内容。我们不能exec ... {} +
在这里使用,因为我们需要它单独作为每个目录的条件。
答案2
如果 busybox 在您的系统上可用,您可以执行以下操作:
busybox find . -type d '(' -exec [ -e '{}/omit.txt' ] ';' -prune \
-o -name '<NAME>' -print ')'
busybox的find
,就像 GNU 的一样,确实扩展{}
到文件的路径,即使它只是部分的争论避免了不得不诉诸sh
,但更重要的是,在最近的版本中,它能够[
在没有 fork() 或 execve() 的情况下运行小程序,因此它比大多数其他find
实现效率高几个数量级。
如果名为的目录<NAME>
本身可能包含 aomit.txt
并且您想在这种情况下打印它,即使仍然被修剪,您可以将其更改为:
busybox find . -type d '(' -exec [ ! -e '{}/omit.txt' ] ';' -o -prune ')' \
-name '<NAME>'
在 bosh (不是 bash)shell 中,find
(like [
) 是内置的,并且能够运行一些 shell 代码,而无需使用其-call
谓词分叉,这也将节省 fork() 和 execve() :
find . -type d '(' -call '[ -e "$1/omit.txt" ]' {} ';' -prune \
-o -name '<NAME>' -print ')'
更便携的替代方案是使用find
'sFile::Find
模块。
perl -MFile::Find -le '
find sub {
if (-e "$_/omit.txt") {
$File::Find::prune = 1;
} else {
print $File::Find::name if ($_ eq "<NAME>") && -d;
}
}, @ARGV' -- .
答案3
@ilkkachu 对我困扰了一段时间的问题给出了很棒的答案!一定要给他们投赞成票。我只是想添加一些我使用过的变体,这可能会让其他人受益:)
示例输出基于以下结构
./
├── a/
│ ├── b/
│ │ └── world.txt
│ └── hello.txt
├── foo.txt
└── some_git_repo/
├── .git/
├── README
└── c/
└── some_git_submodule/
├── .git/
└── README
打印除 git repos 之外的所有目录
find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -prune -o -print \)
.
./a
./a/b
1.打印所有目录,包括git repos
2. 不要递归到任何 git 存储库
find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print -prune -o -print \)
.
./a
./a/b
./some_git_repo
打印所有文件,除了 git 存储库中的文件
find . \( -exec sh -c 'test -e "$1/.git"' sh {} \; -prune -o -type f -print \)
./foo.txt
./a/b/world.txt
./a/hello.txt
1. 打印所有文件,除了 git repos 中的文件
2.打印排除的git目录
find . \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print -prune -o -type f -print \)
./foo.txt
./a/b/world.txt
./a/hello.txt
./some_git_repo
然后相反...
打印所有 git 存储库
find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print -prune \)
./some_git_repo
打印所有 git 存储库,包括子模块
find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print \) -o \( -name '.git' -prune \)
./some_git_repo
./some_git_repo/c/some_git_submodule