diff 程序对文件名中包含非 ASCII 字符的文件给出误报

Nik*_* R. 5 diff macos

例子:

\n
% diff "/Volumes/New Volume/4kyoutube/" "/Volumes/New Volume/tmpmusic"| grep Distortion\nOnly in /Volumes/New Volume/tmpmusic: ZAC & B\xc3\xa4kka - Distortion (Original Mix) [Sprout].mp3\nOnly in /Volumes/New Volume/4kyoutube/: ZAC & B\xc3\xa4kka - Distortion (Original Mix) [Sprout].mp3\n\n% diff "/Volumes/New Volume/tmpmusic/ZAC & B\xc3\xa4kka - Distortion (Original Mix) [Sprout].mp3" "/Volumes/New Volume/4kyoutube/ZAC & B\xc3\xa4kka - Distortion (Original Mix) [Sprout].mp3" \n% \n
Run Code Online (Sandbox Code Playgroud)\n

我能做什么呢?这些文件是相同的。

\n

LSe*_*rni 11

这不是“差异误报”,而是两个文件名被视为不同的.

\n

我的大胆假设是,要么这两个文件夹位于不同的设备上,具有不同的文件编码;要么这两个文件夹位于不同的设备上,并且具有不同的文件编码。或者这两个名字的编码不同,尽管它们在视觉上是相同的。具体来说,两个“B\xc3\xa4kka”之一是“预组合”形式,即 U+00E4 (UTF-8 C3 A4),而另一个是“分解”形式,U+0061 U+0308 (UTF -8 0x61 0xCC 0x88) 带有组合分音符。

\n

我手头没有 MacOS,但我可以在 ext4 Linux 上重现此内容:

\n
$ A=$( echo -e "Ba\\xcc\\x88kka" )\n$ B=$( echo -e "B\\xc3\\xa4kka" )\n$ echo $A $B\nBa\xcc\x88kka B\xc3\xa4kka\n$ touch $A $B\n$ ls -la | grep kka\n-rw-rw-rw-+  1 lserni  users     0 Apr 29 18:14 Ba\xcc\x88kka\n-rw-rw-rw-+  1 lserni  users     0 Apr 29 18:14 B\xc3\xa4kka\n
Run Code Online (Sandbox Code Playgroud)\n

显然,我现在在同一个文件夹中有两个同名的文件

\n

我显然不能确定,但​​你可能也处于同样的困境。

\n

要进行检查,只需运行“diff”的输出hexdump -C,看看是否有类似的内容,

\n
00000020  20 20 20 30 20 41 70 72  20 32 39 20 31 38 3a 31  |   0 Apr 29 18:1|\n00000030  36 20 42 61 cc 88 6b 6b  61 0a 2d 72 77 2d 72 77  |6 Ba..kka.-rw-rw|\n00000060  70 72 20 32 39 20 31 38  3a 31 36 20 42 c3 a4 6b  |pr 29 18:16 B..k|\n00000070  6b 61 0a                                          |ka.|\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,在十六进制转储中,它们立即可见为“Ba..kka”(“a”是普通的“a”,后跟 UTF8“添加分音符”)和“B..kka”(只有一个符号,它是“带分音符号的小拉丁文 a”)。

\n

修理东西

\n

坦率地说,我首先对整个文件夹结构进行规范化。即使您有相同名称的文件,但具有不同的编码(即一些是预组合的,一些是分解的),这迟早会困扰您。

\n

从文件系统的角度来看,您使用哪个系统很大程度上无关紧要。重要的是你现在如何喂养系统以及你现在如何使用系统。

\n

如果新传入的文件具有预组合名称,则将所有 FS 设置为预组合是有意义的(反之亦然),因此将维持标准。另一方面,您可能还想检查诸如搜索文件、排序等功能,以验证文件是否位于您期望的位置(不用说,某些系统认为 a”、“a”) \xcc\x88" 和 "\xc3\xa4" 相同,其他一些则不然 - 他们可能将 "a" 和 "a\xcc\x88" 设置在一起,在其他地方设置 "\xc3\xa4";反之亦然)。

\n

我尝试复制一个名为“a\xcc\x88lphacomposed”、“\xc3\xa4lphadecomposed”和“alphaneutral”的小mp3文件,然后使用包含这三个文件以及“alpha0”的文件夹test”和“alpha z test”,然后是分解的还是预组合的最好(如果有的话)。

\n

该文档似乎表明您应该使用 decomposed

\n

首先,您需要所有文件名的列表。这很容易

\n
find . -type f > list-as-it-is.txt\n
Run Code Online (Sandbox Code Playgroud)\n

但现在您需要将列表中的预组合元素转换为其分解形式。我做了一些研究,更复杂的是,MacOS 和 Linux 的行为似乎有所不同,并且 MacOS 存在几个遗留的适应问题:

\n
\n

重要提示:本问答中使用的术语(预组合和分解)\n大致分别对应于 Unicode 范式 C 和 D。\n但是,大多数卷格式并不遵循这些范式的确切规范。\n 例如,HFS Plus(Mac OS 扩展)使用范式 D 的变体,其中 U+2000 到 U+2FFF、U+F900\n到 U+FAFF 以及 U+2F800 到 U+2FAFF 不被分解(这\n避免了旧 Mac 文本\n编码的往返转换问题。您的卷格式可能也有类似的奇怪之处。

\n
\n

理论上,磁盘上应该只有一种形式(“Mac OS X\ 的 BSD 层对文件名使用规范分解的 UTF-8 编码”)。在实践中,它似乎取决于(显然,否则你不会遇到问题;可以预见的是,你并不孤单)。

\n

因此,我对于建议转换方法非常谨慎,而无法事先在真正的 MacOS 上进行测试。如果文件很少,那么我建议手动修复它们 - 删除一个文件,将另一个文件复制到另一个文件夹中。

\n

理论上,你可以做类似的事情(在 Bash 中)

\n
hexa=$( echo -n "$name" | xxd -ps | tr -d "\\n" )\nif [ $[ 2*${#name} ] -lt ${#hexa} ]; then\n    # Not ASCII.\n
Run Code Online (Sandbox Code Playgroud)\n

或\nif ( echo "$name" | file - | grep "UTF-8" > /dev/null ); 然后

\n

如果测试匹配,你可以这样做

\n
mv "$name" "$(dirname "$name")/tmpname" && mv "$(dirname "$name")/tmpname" "$name"\n
Run Code Online (Sandbox Code Playgroud)\n

也许第一个“mv”将识别该文件,无论其编码如何,而第二个“mv 将使用固定的默认系统编码重新创建名称,这希望适合您。

\n

这种操作会非常快,即使它不必要地处理所有UTF-8 名称。

\n

忽视事物

\n

您可以使用这种技巧忽略所有文件。那么,只有当两个文件不同并且具有不同编码的相同名称时才会出现问题。这是一个问题吗?如果不是,那么一切都准备好了。

\n

只需进行初步操作grep,删除包含“^Only”的行:

\n
diff ... | grep -v ^Only | grep Distortion\n
Run Code Online (Sandbox Code Playgroud)\n

删除重复项

\n

幸运的是,这完全绕过了编码。已经有一些工具可以做到这一点(jdupes这是我使用的)。具有相同内容但 MP3 标签不同的文件将无法使用此方法,您可能会发现此答案很有用。

\n
find folder1 -type f -exec md5sum \\{\\} \\; | sort > folder1.txt\nfind folder2 -type f -exec md5sum \\{\\} \\; | sort > folder2.txt\n
Run Code Online (Sandbox Code Playgroud)\n

现在,如果您想获得重复项:

\n
join -o 2.2 folder1.txt folder2.txt\n
Run Code Online (Sandbox Code Playgroud)\n

将为您提供folder2中重复的文件(-o 2.1将为您提供folder1中的文件)。

\n