我试图验证Bash
中是否存在文件。我知道文件名(在变量中)但不知道扩展名(可以是.pmdl
或.umdl
)。
在OSX上,这有效:
$> ls
ecole.pmdl
$> filename="ecole"
$> ls "$filename."[pu]mdl
ecole.pmdl
但是,当文件名包含重音时,它不会出现:
$> ls
école.pmdl
$> filename="école"
$> ls "$filename."[pu]mdl
ls: école.[pu]mdl: No such file or directory
然而,如果我不使用globbing,它会起作用:
$> ls "$filename."pmdl
école.pmdl
我正在寻找适用于Linux和Linux的简单解决方案。 OSX。 This is the closest question我在那个主题上找到了。
编辑:
$> bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16)
Copyright (C) 2007 Free Software Foundation, Inc.
编辑2:
短版本,以证明在OSX Bash v3.2.57上使用相同的é
字符(系统地)失败。 Linux Bash 4.3.30上的相同场景系统地(找到)工作。
$> touch é.txt
$> ls é*
ls: é*: No such file or directory
答案 0 :(得分:2)
要求HFS + here和here(Apple文件系统)以分解形式存储Unicode字符串(而不是pre-composed character)。
然后,Unicode代码位置U + 0E9的é
之类的字符被分解为Unicode代码位置的两个字符e
和´
分别为U + 065和U + 0301。
您可以通过创建干净的空目录并执行以下操作来查看此差异:
$ a='é'
$ echo "$a" >.text
$ touch "$a"
$ ls > .list
然后比较这两个命令的输出:
$ od -vAn -tx1c .text
c3 a9 0a
303 251 \n
$ od -vAn -tx1c .list
65 cc 81 0a
e 314 201 \n
哪些不相等。
您可以尝试在系统中使用此模式:
ls "e$(echo -e '\xcc\x81')cole".[pu]mdl
这就是é
由文件系统中的两个字符表示的表达式。
了解此问题已在较新的bash版本中得到解决。
参考:
How to enter special characters so that bash terminal understands them
答案 1 :(得分:2)
<强> TL;博士强>
使用以下解决方法之一:
ls "$(iconv -t UTF-8-MAC <<<'école')."[pu]mdl
- 最通用,但很麻烦。ls $'e\x{cc}\x{81}cole'.[pu]mdl
- 难以记住,并且特定于手头的变音符号(急性重音,´
)。ls e?cole.[pu]mdl
- 简单输入并记住,但限于1合并变音符号并可能产生误报。或者:通过Homebrew安装Bash 4.3.30或更高版本并使用它而不是macOS仍然附带的Bash 3.x:brew install bash
。
下面的血腥细节。
关于非ASCII字符,
macOS文件系统, HFS+ ,只说 NFD ( 分解 Unicode规范化表单),其中重音字母由 2个或更多 Unicode代码点表示:基础字母,然后是组合变音符号(重音符号):
é
:
e
(U+0065
,UTF-8编码0x65
)´
之上的U+0301
,UTF-8编码{{1} })。0xcc 0x81
。通常 - 例如,当您在终端或大多数编辑中键入字符时 - NFC ( 撰写使用 Unicode规范化表单),其中(通常)重音字母由 1 Unicode代码点表示:
Ṹ
:单个 Unicode字符é
,则UTF-8编码U+00E9
。0xc3 0xa9
,表示为NFC,确实找到名为{{1}的文件大概存储在NFD中,因为Bash只是将NFC表示传递给 system 函数,该函数确实识别了等价。了解这些 Unicode正常(规范化)表单 here。
简而言之: Bash 应该认识到NFD和NFC表示是等效的,但不是,就像macOS 10.12.1附带的过时版本一样 - Bash 3.2.57 。
虽然至少在BOS 4.3.30 上运行macOS 时问题已解决,但 Apple尚未更新为Bash 4.x 版本许可原因(请参阅下面的解决方案)。
请参阅本文的底部,了解 Linux 世界。
对于在macOS上带有重音字符的通配文件名,有变通方法:
[如果可行]使用Homebrew,安装最新的4.x Bash版本并使用它而不是macOS附带的版本:ls école
。
[健壮,但更精细] 使用école
将Bash字符串文字从NFC转换为NFD,以便与文件系统表示相匹配:
brew install bash
iconv -t UTF-8-MAC
[更简单,但次优]将每个重音字符表示为ls "$(iconv -t UTF-8-MAC <<<'école')."[pu]mdl
,因为从Bash的角度来看,由文件系统报告的重音字符,等于基本字符ls $'e\x{cc}\x{81}cole'.[pu]mdl
后跟另一个字符(组合变音符号;相应地调整多个组合变音符号)。
(这种方法显然不是最理想的,因为它不会匹配只是 <base-char>?
,而是任何以e
开头的双字符序列:
é
许多 Linux 发行版使用的 ext文件系统完全按指定的方式存储文件名 :< / p>
换句话说:使用NFC名称创建的文件存储为具有NFD名称的文件。
因此,e
考虑NFC和NFD的不同形式,因为它们的字节级表示不同,因此它甚至允许(概念上)相同名称的文件仅在Unicode正常形式上不同 - 例如,名为的文件由ls e?cole.[pu]mdl
(ext
)打印时,$'e\xcc\x81cole'
和$'\xc3\xa9cole'
无法区分,但它们是不同的文件(!)。
因此 - 并且适当地 - Linux 上的Bash版本 / p>
警告:ls
,例如,在Ubuntu上充当école
,从Ubuntu 16.04起,不支持区域设置(可识别多字节字符编码) ,至少在 globbing 时:globbing symbol dash
匹配单个字节而不是单个字符(由活动区域设置定义& #39;字符编码,反映在语言环境类别/bin/sh
中,通常为UTF-8)。因此,为了匹配单个非ASCII字符,您需要知道该字符的UTF-8编码组成的字节数,并为每个字节使用?
;例如,NFC LC_CTYPE
(2个字节)必须与?
匹配。 [1]
当你在shebang行为é
的脚本中使用globbing时,这可能很重要。
在实践中,很少遇到NFD字符串,因此使用NFC字符串创建文件并稍后通过globs匹配它们时,macOS体验的不同Unicode正常形式的问题很少出现在Linux上。
[1] ??
旨在成为一个快速的,符合POSIX标准的shell实现(主要是限制到POSIX功能),但在这种情况下它似乎下降简短:part of the POSIX spec. describing the pattern-matching notation清楚地谈到字符,而非字节:#!/bin/sh
Character Sets。
答案 2 :(得分:1)
$ echo "école." | xxd
00000000: c3a9 636f 6c65 0a ..cole.
$ echo "école." | xxd
00000000: 65cc 8163 6f6c 650a e..cole.
所以我们可以看到他们是不同的角色:
$ echo -e "\x65\xCC\x81"
é
$ echo -e "\xC3\xA9"
é
您的文件名中没有使用与您的文件名相同的字符 变量
for i in {1..3}; do f="école"; ls "$f."[pu]mdl; echo "$i: $f."[pu]mdl; done
for i in {1..3}; do f="école"; ls "$f."[pu]mdl; echo "$i: $f."[pu]mdl; done
ls: école.[pu]mdl: No such file or directory
1: école.[pu]mdl
ls: école.[pu]mdl: No such file or directory
2: école.[pu]mdl
ls: école.[pu]mdl: No such file or directory
3: école.[pu]mdl
école.pmdl
1: école.[pu]mdl
école.pmdl
2: école.[pu]mdl
école.pmdl
3: école.[pu]mdl
这个错误很难重现,因为将字符从一个地方复制并粘贴到另一个地方可以通过编辑器,shell等完全改变它来翻译。它可能看起来像是相同的角色,但它看似难以区分的细节真的不同。