【问题标题】:BASH find files with ñ in nameBASH 查找名称中带有 ñ 的文件
【发布时间】:2018-07-15 00:24:35
【问题描述】:

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

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

find . -type f -name *x*

它返回:

./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 '.*[ñ].*'

【问题讨论】:

  • 一个简单的find . -type f -name *ñ* 在 macOS 上为我工作。您使用的是什么操作系统?
  • Mac OSX El Capitan Region 设置为 USA,并在 ~/.bash_profile export LANG=en_US.UTF-8 export LC_ALL=en_US.UTF-8 中导出变量
  • 尝试使用 grep 代替
  • 找到 . -类型 f | grep ñ 也不起作用

标签: regex bash find quoting


【解决方案1】:

(其中一部分是从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 输出“行”末尾的换行符。)但是当您在 MacOS 扩展卷上的文件名中使用它时,它会转换为分解形式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` 这样的括号表达式,就像这样(在带有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 是不是很有趣?

【讨论】:

  • 大声笑,我想要一种直接的方法来用西班牙语或法语创建完整的字母表,比如 mkdir -p {a..z} 但似乎我必须坚持使用 mkdir -p {{a ..n},ñ,{o..z}} 感谢您的出色回答。
猜你喜欢
  • 2011-10-02
  • 2014-07-08
  • 1970-01-01
  • 1970-01-01
  • 2018-12-10
  • 1970-01-01
  • 2012-03-11
  • 2016-09-27
  • 1970-01-01
相关资源
最近更新 更多