为什么

为什么

为什么

我有两个文件夹应该包含完全相同的文件,但是,当我查看文件数量时,它们是不同的。我想知道其中一个而不是另一个中存在哪些文件/文件夹。我的想法是我将列出所有文件,然后使用 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/fordir1dir2/for开头dir2,这将使比较更加困难。
  • 顺序是随机的。
  • 文件路径每行写入一个,但换行符与文件路径中的任何换行符一样有效,或者换句话说,文件路径可以由多行组成,因此输出无法可靠地进行后处理。

这些问题可以通过 GNUfindsort使用以下方法来解决:

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 Column 上:

print -rC1 -- $array

(或NUL 分隔,以便可以通过添加选项进行后处理-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.filelist2.file不会“污染”结果。

相关内容