是否可以在查找命令中选择性地应用最小深度?

是否可以在查找命令中选择性地应用最小深度?

我有一个文件层次结构,例如:

data
├── debug.log
├── messages
│   ├── msg001.txt
│   ├── msg002.txt
│   └── msg003.txt
└── pictures
    ├── msg002
    │   └── pic001.jpg
    └── msg003
        ├── pic001.jpg
        └── pic002.jpg

我想找到所有文件以及前两层以下的所有目录(数据、数据/消息和数据/图片)。所有不属于层次结构固定结构一部分的事物(如果有意义的话)。

我可以通过一次查找调用来完成此操作吗?

我可以找到这些文件:

$ find data -type f | sort
data/debug.log
data/messages/msg001.txt
data/messages/msg002.txt
data/messages/msg003.txt
data/pictures/msg002/pic001.jpg
data/pictures/msg003/pic001.jpg
data/pictures/msg003/pic002.jpg

我可以找到目录:

$ find data -mindepth 2 -type d | sort
data/pictures/msg002
data/pictures/msg003

但我无法将这些结合起来,因为 -mindepth 是一个选项,而不是测试:

$ find data -type f -o \( -mindepth 2 -type d \) | sort
find: warning: you have specified the -mindepth option after a non-option argument -type, but options are not positional (-mindepth affects tests specified before it as well as those specified after it). Please specify options before other arguments.

data/messages/msg001.txt
data/messages/msg002.txt
data/messages/msg003.txt
data/pictures/msg002
data/pictures/msg002/pic001.jpg
data/pictures/msg003
data/pictures/msg003/pic001.jpg
data/pictures/msg003/pic002.jpg

(注意这里没有找到data/debug.log)

有什么方法可以将层次结构的深度视为真正的测试吗?

我能想到的最好的组合是在路径上使用正则表达式来识别目录的前两层:

$ find data -type f -o \( -type d -regextype posix-extended \! -regex 'data(/[^/]+)?' \) | sort

答案1

有什么方法可以将层次结构的深度视为真正的测试吗?

有在FreeBSD 查找,它-depth N还有一个条件:

% find data -type f -o -depth +1 -type d |sort
data/debug.log
data/messages/msg001.txt
data/messages/msg002.txt
data/messages/msg003.txt
data/pictures/msg002
data/pictures/msg002/pic001.jpg
data/pictures/msg003
data/pictures/msg003/pic001.jpg
data/pictures/msg003/pic002.jpg

(是的,这很容易与该-depth选项混淆。)

如果您知道属于“固定结构”的目录集(IMO,如果结构确实是固定的,您应该知道),您可以排除这些目录:

% find data ! -path data ! -path data/messages ! -path data/pictures
...

或与 grep 相同:

% find data | grep -vEe '^(data|data/(pictures|messages))$'
...

(由于您已经使用默认输出格式find, 而不是find -print0,您的文件名可能不包含换行符)

答案2

请注意,这-mindepth是一个非标准扩展(最初来自 GNU,find但后来添加到了一些其他实现中)。与 相反-maxdepth,它很容易用标准谓词来模拟。例如LC_ALL=C find . -path './*/*'模拟 GNU 的find . -mindepth 2.

所以在这里:

LC_ALL=C find data '(' -type d -path '*/*/*' -o -type f ')' -print0 |
  sort -z |
  tr '\0' '\n'

find(除非您使用 NUL 分隔的记录,否则您无法通过管道传输to的输出sort,因为文件路径可以由多行组成。-print0并且-z是 GNU 扩展,-print0现在很常见(很快就会出现 POSIX),但-z不太常见)。

答案3

这不是最漂亮的方法,但您可以使用 GNU 执行以下操作find

find data -printf '%d\0%y\0%p\n' | awk -F '\0' '$2 == "f" || $2 == "d" && $1 >= 2 {print $3}'

find使用该-printf标志将打印以下字段(由空字符 - 分隔\0

  %d     File's depth in the directory tree; 0 means the file is a starting-point.
  %y     File's type (like in ls -l), U=unknown type (shouldn't happen)
  %p     File's name.

然后该命令将打印深度等于或大于 2 ( ) 的awk所有文件 ( ) 和目录的名称。$2 == "f"$2=="d" && $1 >= 2

答案4

免责声明:我是本回复中使用的 rawhide (rh) 程​​序的当前作者(请参阅https://github.com/raforg/rawhide)。

右旋,你可以这样做:

rh data 'f || (d && depth >= 2)'

这会在data目录中搜索文件 ( f) 以及d深度至少为 2 ( depth >= 2) 的目录 ( )。

它适用于 Linux、FreeBSD、OpenBSD、NetBSD、macOS、Solaris 和 Cygwin。

相关内容