如何找到包含匹配文件的所有目录?

如何找到包含匹配文件的所有目录?

我正在寻找包含与模式匹配的文件的目录,例如foobar*.csv.包含此类文件的目录可能包含数百个(并且没有子目录!),所以我想 find 一找到就打印here/is/the/path/to/dirhere/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

使用finds-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 中都可用。

相关内容