我正在寻找包含与模式匹配的文件的目录,例如foobar*.csv
.包含此类文件的目录可能包含数百个(并且没有子目录!),所以我想 find 一找到就打印here/is/the/path/to/dir
并here/is/the/path/to/dir/foobar-2022-01-01.csv
停止下降。
我怎么做?
答案1
find /path/to/base/dir -type f -name "foobar*.csv" -exec dirname {} \; | sort -u
解释:
- 查找所有符合“foobar*.csv”模式的文件。
- 获取每个文件的目录名。
- 对它们进行独特的排序。
这不节省内存,但对于“数百”个文件,需要几毫秒才能得到结果。
答案2
使用 zsh:
dirs=( **/*(/e['()(($#)) $REPLY/foobar*.csv(NY1)']) )
这并不能阻止下降,因为它仍然会尝试查找匹配目录的子目录,Y1
将在第一个匹配处停止foobar*.csv
,但 zsh 仍然需要读取所有(非隐藏)目录的完整内容来查找子目录)。
答案3
使用(类似 POSIX)bosh
壳,其中find
(实际上sfind
) 是内置的,并且有一些可以评估 shell 代码的-call
/谓词:-calldir
find_match() {
find . ! -name . -prune -name "$1" -call 'pwd; return' ';'
false
}
find . -type d -calldir 'find_match "foobar*.csv"' ';' -prune
要对这些匹配目录执行任何操作,请添加:
-call '
dir=$1
whatever you need to do with "$dir"
' {} ';'
对于上面的命令。
-prune
就像标准中一样find
,阻止find
下降到子目录。 AFAICT,sfind
没有 GNU 风格-quit
或 NetBSD 风格-exec [status]
,但看起来return
从-call[dir]
函数内的被调用者进行调用可以达到相同的效果,并使其更加灵活。
答案4
使用find
s-execdir
选项代替-exec
:
find . -iname 'foobar*.csv' -execdir sh -c 'pwd' {} +
这使用了一个sh -c
包装器pwd
(而不是仅仅运行-execdir pwd {} +
),因为pwd
不接受文件名参数,并且如果给定它们就会抱怨。 shell 包装器允许 pwd 在目录中运行,而无需向其传递文件名参数。
或者,如果目录中的匹配文件数量可能超过 ARG_MAX 的数量(在 Linux 上大约为 2MB,因此这种情况不太可能发生),请将输出通过管道传输到uniq
.
find . -iname 'foobar*.csv' -execdir sh -c 'pwd' {} + | uniq
注意:-execdir
是 POSIX 命令的非标准增强find
。它可能在某些版本find
(尤其是古老的和/或专有版本)上丢失。它是在 GNU find 和 BSD find 中都可用。