Bash:查找包含两个文件的文件夹

Bash:查找包含两个文件的文件夹

嗨,我有一个很大的目录树。我想找出所有包含名称以“.ext1”结尾的文件和名称以“.ext2”结尾的文件的目录。

这怎么可能?我考虑过使用两个查找,一个用于“.ext1”,一个用于“.ext2”,但是我需要找到交集,这该怎么做?

谢谢!

答案1

这是一个相对简单的解决方案,它只运行find一次,将其输出存储在临时文件中,然后分离并整理两个扩展的结果。

tmp=$(mktemp)
find . -name '*.ext1' -o -name '*.ext2' | sort >"$tmp"
comm -12 <(<tmp sed -n 's!/[^/]*\.ext1$!!p' | sort) \
         <(<tmp sed -n 's!/[^/]*\.ext2$!!p' | sort)
rm "$tmp"

另一种方法是遍历find目录并使用辅助程序检查模式是否匹配。请注意,在这种情况下存在性检查有效,但如果您的搜索模式不匹配自身并且是可能的文件名,则需要更复杂的东西。

find . -type d -exec sh -c '{ set "$0"/*.ext1; [ -e "$1" ]; } &&
                            { set "$0"/*.ext2; [ -e "$1" ]; }' {} \;

这是一个 zsh 解决方案,其运行方式类似于最后一条命令:

echo **/*(/e\''set -- $REPLY/*.ext1(N[1]) $REPLY/*.ext2(N[1]); ((#==2))'\')

这是另一个 zsh 解决方案,它查找*.ext1并选择仅具有以下内容的目录*.ext2

echo ./**/*.ext1(e\''REPLY=${REPLY:h}; set -- $REPLY/*.ext2(N); ((#))'\')

这是部分 Perl 解决方案;由于 Perl 通配符的变化,如果目录名包含空格,它将不起作用(有办法解决这个问题,但我找不到一种相当优雅的方法)。

perl -l -MFile::Find -e \
  'find {no_chdir => 1,
         wanted => sub {<$_/*.ext1> and <$_/*.ext2> and print}}, "."'

答案2

如果您知道每个文件的确切名称:

find start_dir -type d -exec test -e {}/file.ext1 -a -e {}/file.ext2 \; -print

如果您只知道扩展名,那么这种极其丑陋的黑客攻击就会起作用:

find start_dir -type d -execdir bash -c 'shopt -s nullglob; eval '\''test -n "$(echo '{}'/*.ext1)" -a -n "$(echo '{}'/*.ext2)"'\''' \; -print

如果您有很多目录需要搜索,它也可能会非常慢。

答案3

如果从目录树的头部运行,这似乎有效

find $(find . -name "*.ext1" -printf %h\\n) -name "*.ext2" -printf %h\\n

答案4

继续使用 的另一个答案find,根据评论,它不适用于路径中的空格,可以xargs一起使用 和find [...] -printf来首先找到包含第一个文件名/扩展名的目录,然后使用该目录列表查找第二个文件名/扩展名。例如,给定一些起始目录dir(仅为了便于阅读而分成多行):

$ find dir -name "*.ext1" -exec printf '%q\n' {} \; | \
   xargs -I{} dirname {} | \
   xargs -I{} printf '%q\n' {}  | \
   xargs -I{} find {} -name '*.ext2' -printf '%h\n'

需要注意的是,如果一个目录包含两个(或更多)与任一扩展名匹配的文件,则该目录将出现两次(或更多);如果这是一个问题,只需将其附加... | sort -u到管道即可。

注意:xargs -I{} cmd {}仅用于将命令粘贴到语句cmd中的所需位置xargs。该find命令有一个内置-printf选项,可以引用输出字符串(作为使用 的以空字符结尾的字符串的替代find ... -print0 | xargs -0 ...)。该find命令-print '%h'打印dirname当前参数的。

相关内容