我有一个文件层次结构,例如:
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。