我想找到驻留在任何目录中的所有文件foo
。例如,考虑以下文件:
foo/w
a/foo/x
a/b/foo/y
a/b/c/foo/z
a/b/c/foo/bar/n
我想找到这些文件w,x,y,z
并按上面的方式列出它们,即及其相对路径。我的尝试是这样的
$ find . -path '**/foo' -type f
这是行不通的。搜索不应包括 file n
,即仅包含其父目录名为foo
我们感兴趣的文件。
答案1
不使用find
,而是在zsh
shell 中进行通配:
$ printf '%s\n' **/foo/*(^/)
a/b/c/foo/z
a/b/foo/y
a/foo/x
foo/w
这使用了**
glob,它“递归地”匹配目录,匹配foo
当前目录或下面目录中指定的任何目录,然后*(^/)
匹配这些foo
目录中的任何文件。其(^/)
末尾是一个 glob 限定符,用于限制匹配目录的模式((.)
仅用于匹配常规文件,或(-.)
还包含到常规文件的符号链接)。
在bash
:
shopt -s globstar nullglob
for pathname in **/foo/*; do
if [[ ! -d "$pathname" ]] || [[ -h "$pathname" ]]; then
printf '%s\n' "$pathname"
fi
done
我设置了nullglob
选项以bash
完全删除模式,以防它不匹配任何事物。 shellglobstar
选项允许使用**
in bash
(默认情况下在 中启用zsh
)。
由于bash
没有 的 glob 限定符zsh
,我将循环模式匹配的路径名并测试每个匹配,以确保在打印之前它不是目录。将“ ! -d || -h
”测试更改为“ -f && ! -h
”测试,以仅选择常规文件,或者仅选择单个“ -f
”测试以打印到常规文件的符号链接。
答案2
**
find
在模式中没有特殊含义。-path '*/foo/*'
将查找名为 的目录下的所有文件foo
,包括子目录中的文件。-path '*/foo/*' ! -path '*/foo/*/*'
会排除像a/foo/b/foo/c
.我认为您不能仅通过一次 POSIX 调用来完成此操作find
。
通过find
支持(GNU、BusyBox、FreeBSD、NetBSD)的实现,您可以使用它来-regex
确保./
foo
find . -regex '.*/foo/[^/]*' -type f
或者,您可以使用find
来定位foo
目录和 shell 来枚举该目录中的文件。
另一种可能的方法是find
再次调用,但我找不到find
真正有效的纯 POSIX 解决方案。对于任何 POSIX ,对每个目录find
再次调用:foo
find . -name foo -type d -exec find {} -type d ! -name foo -prune -o -type f \;
请注意,这大部分有效,但不完全有效,而且有点脆弱。您需要-type d -prune
避免递归到子目录,但仅使用-type d -prune
, find 将在foo
目录处停止。! -name foo
不会修剪foo/foo
,因此类似的文件foo/foo/bar
将被报告两次。您不能-exec
在内部使用find
,因为它{}
会被外部解释find
。如果您find
有-maxdepth
(正在考虑将其包含在 POSIX 的下一版本中),您可以使其可靠,但仍然存在以下限制-exec
:
find . -name foo -type d -exec find {} -maxdepth 1 -type f \;
对于任何 POSIX find 和 sh:
find . -name foo -type d -exec sh -c '
for x in "$0/"* "$0/".*; do
if [ -f "$x" ] && ! [ -L "$x" ]; then
…;
fi;
done
' {} \;
将您要在文件名上运行的代码替换为…
.
答案3
我使用的是 RHEL 7。这对我有用:
find . -path "*/foo/*" ! -path '*/foo/*/*' -type f
请注意 -path 之前的点。 (或者替换您的路径,例如 /home/$USER)
这点说“开始在当前目录中查找”
这-小路表示“查找任何内容,后跟名为 foo 的子目录,后跟任何内容”,但嵌套在“foo”下的目录除外。
这-f型说只给我文件在匹配的目录中。
好像
-path "*/foo/*" ! -path '*/foo/*/*'
没有得到一切,因为它错过了诸如 之类的东西./a/foo/b/foo/c
。
如果您可以保证文件和目录名称不包含换行符,您可以使用以下命令对输出进行后处理awk
:
find . -path "*/foo/*" -type f | awk -F/ '$(NF-1) == "foo"'
答案4
第一个想到的是:
find $ROOT_PATH -type d -name foo | xargs -n1 -I{} find {} -type f