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

问题描述 投票:1回答:1

已经尝试了多种解决方案,但似乎都没有。

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

find . -type f -name *x*

它返回:

./alphabet/output/不/剥削.jpg

./alphabet/output/他/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 '.*[ñ].*'
regex bash find quoting
1个回答
2
投票

(其中一部分是从previous answer of mine偷来的。)

Unicode允许一些重音字符以几种不同的方式表示:作为表示重音字符的“代码点”,或表示字符的非重音版本的一系列代码点,后跟重音符号。例如,“ñ”可以表示为预先组合为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”末尾的换行符。)但是当你在MacOS Extended卷上的文件名中使用它时,它会被转换为分解形式U + 006E U + 0303(0x6ecc83):

$touchñ$ 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命令。

解决方案?好吧,在模式中明确使用分解形式有一个icky选项。您可以使用bash的$' ... '引用形式执行此操作,该表单允许使用\x指定十六进制字节:

$ find . -name $'*n\xcc\x83*'
./ñ

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

$ 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支持有趣吗?

© www.soinside.com 2019 - 2024. All rights reserved.