为什么
我有两个文件夹应该包含完全相同的文件,但是,当我查看文件数量时,它们是不同的。我想知道其中一个而不是另一个中存在哪些文件/文件夹。我的想法是我将列出所有文件,然后使用 comm 查找两个文件夹之间的差异。
问题
如何以 /path/to/dir 和 /path/to/dir/file 格式递归创建文件和文件夹列表?
重要笔记
操作系统:Windows 11,子系统 Ubuntu 20.04.4 LTS
位置文件夹:一个网络驱动器,一个本地驱动器
文件夹大小:每个 ~2tb
答案1
注意目录Unix 上的文件只是多种类型的文件之一。使用find
,您可以使用 搜索它们-type d
,或者使用/
zsh glob 中的限定符。其他类型的文件包括常规文件( -type f
,.
全局限定符,也许你的意思是文件),还有符号链接 ( -type l
/ @
)、设备、fifo、套接字...
获取类型的文件目录, 你可以做:
find dir1/ -type d
对于任何其他类型的文件:
find dir1/ ! -type d
对于 也一样dir2
。
现在存在 3 个主要问题:
- 打印的路径将以
dir1/
fordir1
和dir2/
for开头dir2
,这将使比较更加困难。 - 顺序是随机的。
- 文件路径每行写入一个,但换行符与文件路径中的任何换行符一样有效,或者换句话说,文件路径可以由多行组成,因此输出无法可靠地进行后处理。
这些问题可以通过 GNUfind
并sort
使用以下方法来解决:
find dir1/ -type f -printf '%P\0' | LC_ALL=C sort -z
在哪里:
%P
打印文件的路径相对于 dir1- 我们对列表进行排序(在 C 语言环境中,因为文件路径不必由文本组成)
- 我们使用 NUL 分隔的记录而不是行,因为 0 是唯一不能出现在文件路径中的字节。
现在,您可以将该列表与以下内容进行比较:
list() {
find "$@" -printf '%P\0' | LC_ALL=C sort -z
}
echo Directory differences:
comm -z3 <(list dir1/ -type d) <(list dir2/ -type d) | tr '\0' '\n'
echo Non-directory differences:
comm -z3 <(list dir1/ ! -type d) <(list dir2/ ! -type d) | tr '\0' '\n'
该输出无法可靠地进行后处理,因为我们将 NUL 转换回换行符以进行显示,并comm
使用 TAB 来分隔在文件路径中再次有效的列。
或者,您可以获取 zsh 数组中的列表并使用其数组比较运算符:
dirs_in_dir1=( dir1/**/*(ND/:s:dir1/::) )
dirs_in_dir2=( dir2/**/*(ND/:s:dir2/::) )
nondirs_in_dir1=( dir1/**/*(ND^/:s:dir1/::) )
nondirs_in_dir2=( dir2/**/*(ND^/:s:dir2/::) )
然后:
dirs_only_in_dir1=( ${dirs_in_dir1:|dirs_in_dir2} )
dirs_only_in_dir2=( ${dirs_in_dir2:|dirs_in_dir1} )
nondirs_only_in_dir1=( ${nondirs_in_dir1:|nondirs_in_dir2} )
nondirs_only_in_dir2=( ${nondirs_in_dir2:|nondirs_in_dir1} )
并对这些数组执行您必须执行的操作,例如将print
它们r
放在1
C
olumn 上:
print -rC1 -- $array
(或N
UL 分隔,以便可以通过添加选项进行后处理-N
)。
答案2
您不需要任何这些,只需使用diff -qr dir1 dir2
.例如:
$ tree
.
├── dir1
│ ├── file1
│ ├── file3
│ ├── file4
│ ├── file6
│ ├── file7
│ ├── file8
│ └── subdir1
│ ├── dsaf
│ ├── sufile1
│ └── sufile3
└── dir2
├── file1
├── file2
├── file3
├── file4
├── file9
└── subdir1
├── sufile1
└── sufile3
4 directories, 16 files
如果我现在在两个目录上运行diff -qr
(-r
对于“递归”并且-q
仅报告文件何时不同,而不显示实际差异),我得到:
$ diff -qr dir1/ dir2/
Only in dir2/: file2
Only in dir1/: file6
Only in dir1/: file7
Only in dir1/: file8
Only in dir2/: file9
Only in dir1/subdir1: dsaf
也就是说,获取文件列表的方法是find
:
$ find dir1 -type f
dir1/subdir1/dsaf
dir1/subdir1/sufile1
dir1/subdir1/sufile3
dir1/file6
dir1/file1
dir1/file8
dir1/file4
dir1/file7
dir1/file3
然后,您可以删除dir1/
和dir2/
using sed
,并使用比较两个目录的输出流程替代在支持它的 shell 中:
$ comm -3 <(find dir1 -type f | sed 's|dir1/||' | sort) <(find dir2 -type f | sed 's|dir2/||' | sort)
file2
file6
file7
file8
file9
subdir1/dsaf
请注意,这假定文件名没有换行符。如果您需要处理这些问题,只需使用diff -r
上面的方法即可。
答案3
尝试
cd /path/1
find . -type d -print | sort > list1.dir
find . -type f -print | sort > list1.file
cd /path/2
find . -type d -print | sort > list2.dir
find . -type f -print | sort > list2.file
sort
用于确保相同的顺序,以及较小的diff
结果comm
- 您可以使用绝对目标文件名,这样
list1.file
就list2.file
不会“污染”结果。