具有两个或更多文件的目录


11

我想找到当前目录的子目录(即子目录),其中包含2个或更多常规文件。

我对包含少于2个文件的目录不感兴趣,对仅包含子目录的目录也不感兴趣。

Answers:


12

这是基于GNU find和的完全不同的方法uniq。这比基于执行shell命令(对找到的每个目录的文件计数)的答案要快得多,并且对CPU友好得多。

find . -type f -printf '%h\n' | sort | uniq -d

find命令将打印层次结构中所有文件uniq的目录,并且仅显示至少出现两次的目录。


2
您不应该解析的输出find。在这种情况下,因为GNU find会破坏具有在当前语言环境中不可打印的字符的目录名称(例如C语言环境中的“ä”)。又见unix.stackexchange.com/questions/321697/...
Kusalananda

4
@Kusalananda,而不是在输出未输出到tty时。在这里,唯一的问题是与换行符,您可以通过使用修复-printf '%h\0' | sort -z | uniq -zd | xargs -r0 ...
斯特凡Chazelas

6
find . -type d \
    -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' \
    -print

这将在当前目录中或当前目录下找到所有名称,然后过滤掉不是目录名称的所有名称。

其余的目录名称将被赋予以下简短脚本:

c=0
for n in "$1"/*; do
    [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 ))
done

[ "$c" -ge 2 ]

该脚本将计算作为第一个命令行参数(from find)给出的目录中常规文件(跳过符号链接)的数量。脚本中的最后一个命令是测试,以查看计数是否为2或更大。该测试的结果是脚本的返回值(退出状态)。

如果测试成功,-print将导致find打印出该目录的路径。

要同时考虑隐藏文件(名称以点开头的文件),请更改sh -c脚本

for n in "$1"/*; do

for n in "$1"/* "$1"/.*; do

测试:

$ tree
.
`-- test
    |-- a
    |-- dir1
    |   |-- a
    |   |-- b
    |   `-- c
    `-- dir2
        |-- dira
        |-- dirb
        |   |-- file-1
        |   `-- file-2
        `-- dirc

6 directories, 6 files

$ find . -type d -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' -print
./test/dir1
./test/dir2/dirb

您的解决方案不计算名称以点开头的文件。您还应该初始化c = 0以避免目录中不包含任何文件的错误消息。
xhienne

@xhienne我考虑了隐藏文件,并将添加有关此文件的注释。如果目录中没有常规文件,则没有错误,因为这[ "" -ge 2 ]是有效的测试。
库沙兰丹

不确定如何定义“有效”。POSIX要求arg1为整数值。dashbash --posix并且test全部显示错误消息并退出并显示2(即“发生错误”)
xhienne

@xhienne啊,我正在以mas ksh身份运行的系统上进行测试sh。将立即修改。谢谢你戳我!:-)
库萨兰达

此外,[ -f ... ]取消引用符号链接。您应该添加测试以消除它们,因为该问题指定仅应计数常规文件。
xhienne

6

借助GillesSU 的回答及其反面和一些修改,这里是您需要的。

find . -type d -exec sh -c 'set -- "$1"/*;X=0; 
    for args; do [ -f "$args" ] && X=$((X+1)) ;done; [ "$X" -gt 1 ] ' _ {} \; -print

目录树。

.
├── test
│   ├── dir1
│   │   ├── a
│   │   ├── b
│   │   └── c
│   ├── dir2
│   │   ├── dira
│   │   │   └── a file\012with\012multiple\012line
│   │   ├── dirb
│   │   │   ├── file-1
│   │   │   └── file-2
│   │   └── dirc
│   ├── diraa
│   ├── dirbb
│   ├── dircc
│   └── x
│   └── x1
│   └── x2
└── test2
    ├── dir3
    └── dir4

结果:

./test
./test/dir1
./test/dir2/dirb

我一开始也有这个问题,但是包含多个子目录文件的目录会出现问题。它还不会清除仅包含子目录的目录。
库萨兰达

它并不能真正解决。它在我的测试设置中同时找到testdir2目录(请参阅我的答案)。
库萨兰达

适用于您的示例,但也可以添加test/x1test/x2作为文件...,$1并且$2将是的目录test,并且该目录将丢失。
库沙兰达

@Kusalananda除了您的回答,我没有找到其他方法,我试图更改命令的某些部分以使其与您的命令不完全相同(我没有像您那样排除隐藏文件),对不起。
αғsнιη

1
不用担心:-)
库萨兰达

3

find+ wc方法:

find path/currdir -maxdepth 1 -type d ! -empty ! -path "path/currdir" \
-exec sh -c 'count=$(find "$1" -maxdepth 1 -type f | wc -l); [ $count -ge 2 ]' _ {} \; -print

  • path/currdir -当前目录的路径

  • -maxdepth 1-仅考虑直接子文件夹

  • ! -empty -忽略空的子文件夹

  • ! -path "path/currdir" -忽略当前目录路径

  • count=$(find "$1" -maxdepth 1 -type f | wc -l)- count为找到的每个子文件夹分配文件数

  • [ $count -ge 2 ] ... -print -打印包含2个或更多常规文件的子文件夹名称/路径

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.