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 是不是很有趣?
已经尝试了多种解决方案,但 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 是不是很有趣?