BASH 查找名称中带有 ñ 的文件

BASH find files with ñ in name

已经尝试了多种解决方案,但 none 似乎可行。

例如,如果我尝试下一个命令,它会按预期工作

find . -type f -name *x*

它returns:

./alphabet/output/b/box.jpg

./alphabet/output/t/taxi.jpg

但如果我尝试使用西班牙字母表中的任何特殊字符,该命令将不起作用

find . -type f -name *ñ*

结果为空。

如果我尝试

find . -type f -name *n*

然后它还会显示带有特殊字符 ñ

的文件名

如果我尝试为命令设置 LANG 变量,它也不起作用

LANG=C find . -type f -name *ñ*

或使用正则表达式

LANG=C find . -type f -name *.jpg -regex '.*[ñ].*'

(部分内容盗自 previous answer of mine。)

Unicode 允许以几种不同的方式表示一些重音字符:作为 "code point" 表示重音字符,或者作为一系列代码点表示字符的非重音版本,后跟重音符(秒)。例如,“ñ”可以表示为预组合为 U+00F1(UTF-8 0xc3b1,带波浪号的拉丁文小写字母 n)或分解为 U+006E U+0303(UTF-8 0x6ecc83,拉丁文小写字母 n + 组合波浪号).

OS X 的 HFS+ 文件系统要求所有文件名都以 UTF-8 表示形式存储,以完全分解形式(除了一些与此处无关的例外)。在 HFS+ 文件名中,“ñ”必须编码为 0x6ecc83。

当您在键盘上键入“ñ”时,它使用组合形式 U+00F1 (0xc3b1)。您可以通过十六进制转储看到这一点:

$ echo ñ | xxd
00000000: c3b1 0a                                  ...

(注意:“0a”是 echo 输出的 "line" 末尾的换行符。)但是当你在 Mac 上的文件名中使用它时OS 扩展卷,它被转换为分解形式 U+006E U+0303 (0x6ecc83):

$ 触摸 ñ $ ls | xxd 00000000: 6ecc 830a n...

在 UTF-8 语言环境中,这两个不同的表示应被视为相同的字符,但显然 macOS 中的 find 不正确:

$ LC_ALL=en_US.UTF-8 find . -name '*ñ*'
$ LC_ALL=en_US.UTF-8 find . -name '*n*'
./ñ
$ LC_ALL=en_US.UTF-8 find . -name 'n?'
./ñ

在第二个和第三个命令中,find 与 "n" 代码点匹配,并将组合波浪号视为跟在它后面的完全独立的字符。顺便说一句,请注意,我在匹配模式周围加上了引号——这很重要,因为如果没有它们,shell 将在传递它之前 将其扩展为当前目录中的文件名列表 find 命令。

解决办法?好吧,在模式中显式使用分解形式有一个棘手的选择。您可以使用 bash 的 $' ... ' 引用形式执行此操作,它允许使用 \x:

指定十六进制字节
$ find . -name $'*n\xcc\x83*'
./ñ

但实际上比这更糟,因为从 macOS High Sierra 开始,Apple 使用新的 Apple 文件系统 (APFS),它允许 both 表示.由于 find 无法将它们识别为字符,因此您甚至不能像这样使用 -name *[ññ]*' to match both of them, you have to use an extended regular expression with-Eand-regex` 这样的括号表达式(在 Mac 使用 APFS):

$ touch composed-ñ decomposed-n$'\xcc\x83' unaccented-n
$ ls
composed-ñ  decomposed-ñ    unaccented-n
$ ls | xxd
00000000: 636f 6d70 6f73 6564 2dc3 b10a 6465 636f  composed-...deco
00000010: 6d70 6f73 6564 2d6e cc83 0a75 6e61 6363  mposed-n...unacc
00000020: 656e 7465 642d 6e0a                      ented-n.
$ find -E . -regex $'.*(\xc3\xb1|n\xcc\x83).*'
./composed-ñ
./decomposed-ñ

(请注意,在正则表达式中,.* 是您匹配任何字符序列的方式,相当于普通 "glob" 通配符模式中的 *。)

自己动手支持 Unicode 是不是很有趣?