在 ext4 上,将 File 重命名为 file 可以正常工作,但在 exFAT filesystem 上会失败。本文将解释为什么 exFAT 将这两个名称视为相同,它的 Unicode 大写表如何工作,以及执行 仅大小写重命名(case-only renames) 的最简单方法。

exFAT 不允许仅更改字母大小写

你打开终端并运行一个简单的命令:

mv Desktops desktops

但你没有重命名文件夹,而是得到了这个错误:

mv: cannot move 'Desktops' to a subdirectory of itself, 'desktops/Desktops'

起初,这个错误看起来令人困惑。毕竟,你只是想将一个大写字母改为小写。

好消息是 mv 命令本身没有问题。真正的原因是你的 filesystem。

让我们看看为什么会发生这种情况,exFAT 在底层是如何工作的,以及为什么这个错误实际上是有道理的。

什么是 exFAT?

exFAT(扩展文件分配表) 是微软为闪存盘、SD 卡和外部存储设备设计的一种 filesystem。

它支持比 FAT32 大得多的 file 和分区,因此成为 USB 闪存盘、便携式 SSD 和存储卡的流行选择。如今,Windows、macOS 和 Linux 都支持 exFAT,使其成为在不同操作系统之间移动存储设备时最容易使用的 filesystem 之一。

然而,exFAT 也遵循一些 Windows-style 的 filename 规则。其中一条规则是,在比较 filename 时忽略大小写。这个设计选择正是为什么将 Desktops 改为 desktops 的行为与大多数 Linux filesystem 不同的原因。

你何时可能遇到这个问题?

当你使用格式化为 exFAT 的 USB 闪存盘、便携式 SSD、SD 卡或存储卡时,最常遇到这种行为。

如果你在 Linux 系统的内部驱动器上工作,你可能使用的是 ext4 等其他 filesystem,因此仅更改大小写的重命名通常可以按预期工作。

为什么会发生这种情况:简短回答

如果你的驱动器使用 exFAT,filesystem 会将以下名称视为相同:

  • Desktops
  • desktops
  • DESKTOPS

换句话说,exFAT 在比较 filename 时忽略大小写。但是,它仍然会记住你使用的大小写,并完全按照你输入的方式显示 filename。

这种行为被称为 不区分大小写但保留大小写。

因此,仅更改大小写并不像看起来那么简单。

为什么 ext4 可以重命名而 exFAT 不能

许多人认为 ext4 的重命名功能比 exFAT 更好。

事实并非如此。

两种 filesystem 都支持重命名 file 和文件夹。区别在于 它们如何查找 filename。

在 mv 重命名任何内容之前,它会向 filesystem 询问一个简单的问题:

“目标名称的文件或文件夹是否已存在?”

答案完全取决于 filesystem 如何比较名称。

ext4 如何查找名称

将目录视为一个 filename 列表。当 ext4 搜索该列表时,它会精确比较每个存储的 filename。

这意味着以下是三个完全不同的名称:

Desktops
desktops
DESKTOPS

假设你的目录包含:

Desktops

现在你运行:

mv Desktops desktops

ext4 搜索一个与 desktops 完全匹配的 filename。

它没有找到。

从 ext4 的角度来看:

  • Desktops 存在。
  • desktops 不存在。

由于没有冲突,filesystem 只需用新名称更新目录条目。

重命名一步完成。

exFAT 如何查找名称

exFAT 的工作方式非常不同。

它不是直接比较 filename,而是先将两个名称转换为一种通用形式,然后再进行比较。

为此,exFAT 使用存储在 filesystem 内部的一种特殊数据结构,称为 大写表。

与 ext4 不同,比较 不 使用原始字母。相反,两个名称首先被规范化。

什么是大写表?

大写表 是 exFAT filesystem 定义的独特结构之一。

它包含 Unicode 映射,将小写字符转换为对应的大写字符。

例如,该表包含如下映射:

a → A
b → B
d → D
é → É
δ → Δ

该表包含数千个 Unicode 映射,而不仅仅是英文字母。

由于映射位于 filesystem 内部,每个操作系统都可以使用完全相同的规则比较 filename。

exFAT 如何比较文件名

假设你的目录包含这个文件夹:

Desktops

现在你运行:

mv Desktops desktops

在比较名称之前,exFAT 使用大写表转换两个名称。

概念上,它看起来像这样:

Stored name:
Desktops
↓
DESKTOPS
New name:
desktops
↓
DESKTOPS

转换后,两个名称都变成:

DESKTOPS

从 exFAT 的角度来看,它们是相同的。

所以当 mv 询问:

“desktops 是否已存在?”

filesystem 回答:

“是。”

因为规范化后,它确实存在。

为什么存在大写表

你可能会想,为什么 exFAT 要存储一个表,而不是简单地自己转换字母。

答案是 Unicode。

许多语言包含的大小写字符比英文字母复杂得多。

exFAT 不是要求每个操作系统硬编码相同的 Unicode 转换规则,而是将转换表存储在 filesystem 内部。

这提供了一些优势。

首先,每个操作系统使用相同的规则比较 filename。

其次,Unicode 映射可以演变,而无需重新设计 filesystem。

最后,不同的操作系统之间保持兼容,因为它们都使用存储在磁盘上的相同转换表。

这是一个相当优雅的设计。

为什么 exFAT 仍然保留大小写

尽管 exFAT 在比较时忽略大小写,但它仍然会完全按照你输入的方式存储原始 filename。

假设你创建:

MyHolidayPhotos

目录将显示:

MyHolidayPhotos

它 不会 更改大小写。

然而,在搜索文件时,以下所有名称都会匹配:

MyHolidayPhotos
myholidayphotos
MYHOLIDAYPHOTOS

这就是为什么 exFAT 被描述为 保留大小写 但 不区分大小写。

为什么错误看起来如此奇怪

现在让我们回到原始命令。

mv Desktops desktops

在重命名任何内容之前,mv 会检查目标是否已存在。

在 exFAT 上,filesystem 报告 desktops 已存在,因为它比较名称时不考虑大小写。

此时,mv 假设你想将 Desktops 目录移动到一个名为 desktops 的现有目录中。

概念上,它看到类似这样的内容:

Desktops/
└── Desktops/

这将导致在自身内部创建一个目录。

由于这是不可能的,mv 停止并打印:

mv: cannot move 'Desktops' to a subdirectory of itself, 'desktops/Desktops'

命令并没有混淆。它只是相信 filesystem 告诉它的内容。

错误消息来自 mv,但行为来自 exFAT 比较 filename 的方式。

在 exFAT 上重命名仅大小写不同的文件和文件夹

最简单的解决方案是使用临时名称。

mv Desktops temp-desktops
mv temp-desktops desktops

临时名称消除了冲突。一旦原始名称不再存在,第二次重命名就会成功。

虽然这需要两个命令,但它是 exFAT 上最简单、最可靠的方法。

更多示例

示例 1:照片文件夹

假设你的外部 SSD 包含:

photos2026

你想要:

Photos2026

如果你尝试使用 mv 命令重命名它,如下所示:

mv photos2026 Photos2026

它会失败。

相反,使用临时名称在 exFAT 上重命名 file,如下所示:

mv photos2026 Photos-temp
mv Photos-temp Photos2026

示例 2:音乐文件夹

当前文件夹:

RockMusic

期望名称:

rockmusic

同样,使用中间名称。

mv RockMusic rock-temp
mv rock-temp rockmusic

同样的技巧也适用于 file。

这在每个 Linux 文件系统上都会发生吗?

不会。大多数 Linux filesystem 默认是 case-sensitive 的。

例如,ext4 允许以下所有名称存在于同一目录中:

Project
project
PROJECT

因此,以下操作无需额外步骤即可工作:

mv Project project

Btrfs 和 XFS 通常也是如此。

哪些文件系统忽略大小写?

如果你主要使用外部 USB 驱动器,你很可能会遇到这种行为,因为许多便携式驱动器都格式化为 exFAT。

如何检查你的文件系统

如果你不确定驱动器使用哪种 filesystem,请运行:

df -T .

或者:

findmnt -T .

或者,如果你只想要 filesystem 类型:

findmnt -n -o FSTYPE -T .

如果输出显示:

exfat

那么这种行为是预期的。

你可以在以下教程中找到更多检查 filesystem 类型的方法:

关键要点

仅将大写字母改为小写看起来像是一个简单的重命名。

但是,exFAT 比较 filename 的方式与大多数 Linux filesystem 不同。

请记住以下几点:

  • exFAT 比较 filename 时不考虑大小写。
  • 它通过内置的 Unicode 大写表 来实现这一点。
  • Desktops、desktops 和 DESKTOPS 都被比较为相同的名称。
  • mv 在检查目标是否已存在时信任 filesystem。
  • 因此,仅更改大小写的重命名在 exFAT 上通常会失败。
  • 通过临时名称重命名是最简单、最可靠的解决方案。

一旦你理解了 exFAT 如何查找 filename,错误消息就不再神秘。它只是 filesystem 设计方式的结果。

无需 exFAT 驱动器即可自行尝试(可选)

本节是 可选的。你 不需要 外部 USB 驱动器或 SSD 来跟随操作。相反,你可以使用 Linux loop 设备 在磁盘映像内创建一个临时的 exFAT filesystem。

Loop 设备允许 Linux 将普通 file 视为真正的块设备,例如 USB 驱动器或 SSD。这使得它成为一种安全的实验方式,无需修改任何物理存储。完成后,只需卸载 filesystem 并删除映像 file。

创建测试环境

首先,安装所需的工具:

sudo apt update
sudo apt install exfatprogs

接下来,创建一个 100 MiB 磁盘映像:

truncate -s 100M exfat_test.img

将映像附加到空闲的 loop 设备,并将分配的设备名称保存在 shell 变量中:

LOOP=$(sudo losetup --find --show exfat_test.img)

创建 exFAT filesystem:

sudo mkfs.exfat "$LOOP"

创建挂载点并挂载 filesystem:

mkdir mnt_exfat
sudo mount -t exfat \
-o uid=$(id -u),gid=$(id -g) \
"$LOOP" mnt_exfat

uid 和 gid 挂载选项使你的用户成为已挂载 exFAT filesystem 的所有者。这允许你创建、重命名和删除 file,而无需使用 sudo,使本 guide 中的示例更易于跟随。

测试命令

切换到已挂载的 filesystem:

cd mnt_exfat

创建一个测试目录:

mkdir Desktops

现在尝试本文中讨论的命令:

mv Desktops desktops

你应该会看到与真实 exFAT 格式的 USB 驱动器或 SSD 上相同的行为。

仅更改大小写的重命名在 exFAT 上失败.png

清理

完成后,卸载 filesystem、分离 loop 设备并删除临时 file:

cd ..
sudo umount mnt_exfat
sudo losetup -d "$LOOP"
rm exfat_test.img
rmdir mnt_exfat

你需要 exfat-fuse 吗?

在现代 Linux 发行版上,通常不需要。

Linux 内核自版本 5.4 起包含了原生 exFAT 驱动程序,大多数当前发行版默认使用它。在大多数情况下,安装 exfatprogs 就足够了,因为它提供了诸如以下工具:

  • mkfs.exfat
  • fsck.exfat

较旧的 Linux 系统通常依赖:

  • exfat-fuse
  • fuse3

这些软件包在内核获得原生驱动程序之前提供了 exFAT 支持。它们在某些发行版上仍然可用,但除非你使用的是较旧的 Linux 系统或有意测试 FUSE 实现,否则通常不需要它们。

常见问题解答(FAQ)

问:为什么当我只更改大小写时,mv 会显示“自身的子目录”?

答:因为 exFAT 将 Desktops 和 desktops 视为相同的目录名称。当 mv 检查目标是否存在时,filesystem 报告它存在。然后 mv 假设你试图将目录移动到自身内部,并打印相应的错误消息。

问:这在 ext4、Btrfs 或 XFS 上会发生吗?

答:默认情况下不会。这些 filesystem 是 case-sensitive 的,因此 Desktops 和 desktops 被视为不同的名称。直接重命名通常无需额外步骤即可工作。

问:这会影响 Windows 和 macOS 吗?

答:是的。exFAT 在设计上是不区分大小写的,因此 Windows、macOS 和 Linux 在访问 exFAT 卷时都使用相同的规则比较 filename。

问:我可以让 exFAT 区分大小写吗?

答:不能。不区分大小写的 filename 查找是 exFAT filesystem 规范的一部分。Linux 无法通过挂载选项或配置设置启用区分大小写。

问:两步重命名会复制我的 file 吗?

答:不会。两个命令都只是在同一 filesystem 内重命名目录。它们不会复制内容或重新创建目录。

问:我的重命名仍然失败。我应该检查什么?

答:确保临时名称不存在。还要确认你对目录具有写权限,并且源和目标位于同一个 exFAT filesystem 上。

问:我需要一个 exFAT USB 驱动器来尝试这个吗?

答:不需要。你可以使用 Linux loop 设备在磁盘映像内创建一个临时的 exFAT filesystem。本 guide 的可选部分向你展示了如何安全地设置、测试和删除它。

结论

这种行为让许多 Linux 用户感到惊讶,因为大多数 Linux filesystem 是 case-sensitive 的。

但是,exFAT 主要是为与 Windows 和可移动存储的兼容性而设计的。它使用 Unicode 大写表确保每个操作系统一致地比较 filename,同时仍然完全按照用户创建的方式显示它们。

理解这个设计不仅有助于解释为什么 mv Desktops desktops 会失败,还能解释为什么两步重命名每次都有效。

推荐阅读:

保留大小写的 filesystem exFAT exFAT 不区分大小写 exFAT 重命名为小写 exFAT 大写表 filesystem Linux Linux 基础 Linux 命令 Linux exFAT 重命名 Linux 教程 Linux 技巧 将 file 从大写重命名为小写 Linux 大写表