有没有办法递归调用find?
我想仅在与另一个模式匹配的目录中搜索与给定模式匹配的文件。
基本上:
for each (sub)directory D matching "*.data"
do
for each file F in directory D (with subdirs) matching "*.important.txt"
do
run command foo on F
done
done
现在,如果我忽略最内在的要求(在 F 中运行命令 foo),这很简单:
find . -type d -name "*.data" \
-exec find \{\} -type f -name "*.important.txt" \;
但是,我还没有找到将命令传递到内部的方法find
。例如打印出以下内容查找:缺少“-exec”参数每次调用内部查找时:
find . -type d -name "*.data" \
-exec find \{\} -type f -name "*.important.txt" \
-exec "foo \{\} \;" \;
任何解决方案都应该符合 posix 标准(可在/bin/sh
脚本中运行),尤其是。我不是在寻找解决方案
- 将内部查找包装到单独的 shell 脚本中
- 将内部查找包装到 bash 函数中
答案1
要运行find
它自己的结果,您可以使用(或)-c
的参数来防止外部 find 命令特殊对待内部。但是,您随后需要将外部查找的结果作为参数传递给,可以使用 进行扩展:sh
bash
{}
sh
$0
find . -type d -name "*.data" \
-exec sh -c 'find "$0" -type f -name "*.important.txt" -exec echo \{\} \;' \{\} \;
注意:$0
应加引号 ( "$0"
) 以防止目录名称包含空格的问题。
这并不是真正的“递归”解决方案,因为它不允许在没有一些毛茸茸的转义的情况下任意深度嵌套,但它确实支持find -exec
您在示例中要求的两个级别 s 。
如果您的示例与实际问题类似,您也可以尝试使用参数-path
来查找:
find . -path '*.data/*important.txt'
答案2
bash 版本(不兼容 POSIX)
#!/bin/bash
find . -type d -name 'a *' -print0 \
| while IFS= read -r -d '' dir ; do
find "$dir" -type f -name "*.c" -exec echo \{\} \;
done
问题:
(坏)sh 版本(符合 POSIX)
#!/bin/sh
# WARNING: while this will work on directory names with spaces,
# it will break on directory names that contain newlines
find . -type d -name 'a *' -print \
| while IFS= read -r dir ; do
find "$dir" -type f -name "*.c" -exec echo \{\} \;
done
问题:如评论中所述,它将在包含换行符的目录名称上中断。您可能认为这不是一个现实的问题,但这会给您的脚本增加不必要的脆弱性。也许另一个程序有一个错误,会创建这样的目录等。
(更好)sh版本
顺便提一句。如果您需要脚本兼容 POSIX,那么使用shellcheck
。例如,它会注意到read -d
POSIX 中没有定义。