查找名为 foo 的目录中的所有文件

查找名为 foo 的目录中的所有文件

我想找到驻留在任何目录中的所有文件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,而是在zshshell 中进行通配:

$ 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

相关内容