如何在 macOS 上重命名带有重音符号的文件名?

lap*_*pin 5 osx regular-expression rename unicode locate

我正在尝试重命名包含字符“à”的文件。

我执行以下操作:

rename -v 's/à/a/g' *
Run Code Online (Sandbox Code Playgroud)

但它显示所有文件都没有改变。详细模式显示相同的内容。

我试图逃脱 \但没有运气。

我怎样才能让正则表达式匹配这种类型的字符?

编辑

的输出perl -V

Summary of my perl5 (revision 5 version 18 subversion 2) configuration:

  Platform:
    osname=darwin, osvers=16.0, archname=darwin-thread-multi-2level
    uname='darwin osx320.apple.com 16.0 darwin kernel version 15.0.0: wed jun 22 17:57:08 pdt 2016; root:xnu-3247.1.106.2.9~1development_x86_64 x86_64 '
    config_args='-ds -e -Dprefix=/usr -Dccflags=-g  -pipe  -Dldflags= -Dman3ext=3pm -Duseithreads -Duseshrplib -Dinc_version_list=none -Dcc=cc'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=define, usemultiplicity=define
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-arch x86_64 -arch i386 -g -pipe -fno-common -DPERL_DARWIN -fno-strict-aliasing -fstack-protector',
    optimize='-Os',
    cppflags='-g -pipe -fno-common -DPERL_DARWIN -fno-strict-aliasing -fstack-protector'
    ccversion='', gccversion='4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='cc -mmacosx-version-min=10.12.5', ldflags ='-arch x86_64 -arch i386 -fstack-protector'
    libpth=/usr/lib /usr/local/lib
    libs= 
    perllibs=
    libc=, so=dylib, useshrplib=true, libperl=libperl.dylib
    gnulibc_version=''
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
    cccdlflags=' ', lddlflags='-arch x86_64 -arch i386 -bundle -undefined dynamic_lookup -fstack-protector'


Characteristics of this binary (from libperl): 
  Compile-time options: HAS_TIMES MULTIPLICITY PERLIO_LAYERS
                        PERL_DONT_CREATE_GVSV
                        PERL_HASH_FUNC_ONE_AT_A_TIME_HARD
                        PERL_IMPLICIT_CONTEXT PERL_MALLOC_WRAP
                        PERL_PRESERVE_IVUV PERL_SAWAMPERSAND USE_64_BIT_ALL
                        USE_64_BIT_INT USE_ITHREADS USE_LARGE_FILES
                        USE_LOCALE USE_LOCALE_COLLATE USE_LOCALE_CTYPE
                        USE_LOCALE_NUMERIC USE_PERLIO USE_PERL_ATOF
                        USE_REENTRANT_API
  Locally applied patches:
    /Library/Perl/Updates/<version> comes before system perl directories
    installprivlib and installarchlib points to the Updates directory
  Built under darwin
  Compiled at Feb  6 2017 22:16:22
  @INC:
    /Library/Perl/5.18/darwin-thread-multi-2level
    /Library/Perl/5.18
    /Network/Library/Perl/5.18/darwin-thread-multi-2level
    /Network/Library/Perl/5.18
    /Library/Perl/Updates/5.18.2
    /System/Library/Perl/5.18/darwin-thread-multi-2level
    /System/Library/Perl/5.18
    /System/Library/Perl/Extras/5.18/darwin-thread-multi-2level
    /System/Library/Perl/Extras/5.18
    .
Run Code Online (Sandbox Code Playgroud)

编辑 2:

的输出locale

LANG=
LC_COLLATE="C"
LC_CTYPE="UTF-8"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=
Run Code Online (Sandbox Code Playgroud)

解决方案

简而言之,这是有效的。所有 3 个解决方案都完成了这项工作:

  1. rename -nv $'s/a\xcc\x80/a/g' *
  2. PERL_UNICODE=AS rename -n 's/\pM//g' ./*. (请参阅所选答案中的解释)
  3. 切换到zsh, 而不是 MacOS 的默认 Shell ( bash),然后我的原始命令(无需指定诸如 之类的组合字符a\u300)工作:rename -v 's/à/a/g' *

如果您对这些解决方案中的任何一个都不满意,请查看所选答案以找到有用的提示。

Sté*_*las 5

至少在 macOS 和 HFS+ 文件系统上,重音字符以其分解形式à编码,因此编码为a\u300a后跟组合重音符 组合字符),即使您使用touch $'\ue0'(预组合形式(独立a带有严重的口音),导致各种错误(以及Linus Torvald 著名的咆哮之一的主题),例如其伪大小写不敏感。

你会注意到,如果你这样做:

touch à; echo ?
Run Code Online (Sandbox Code Playgroud)

要列出由一个字符组成的文件名,它在以下情况下不返回任何内容:

echo ??
Run Code Online (Sandbox Code Playgroud)

或者

echo *a*
Run Code Online (Sandbox Code Playgroud)

à确实返回(实际上a?)。和:

$ echo ?? | uconv -x name
\N{LATIN SMALL LETTER A}\N{COMBINING GRAVE ACCENT}\N{<control-000A>}
Run Code Online (Sandbox Code Playgroud)

所以你需要:

rename $'s/a\u300/a/g' ./*
Run Code Online (Sandbox Code Playgroud)

(假设zsh或兼容的外壳)。或者使用手动指定该 U+0300 字符 (0xcc 0x80) 的 UTF-8 编码,对于支持 ksh93$'...'引号但不支持zsh's 的shell $'\u300'(如bash在 macOS上找到的古代版本):

rename $'s/a\xcc\x80/a/g' ./*
Run Code Online (Sandbox Code Playgroud)

或者让我们直接perl解释这些\xcc\x80序列:

rename 's/a\xcc\x80/a/g' ./*
Run Code Online (Sandbox Code Playgroud)

或 unicode 字符:

PERL_UNICODE=AS rename 's/\x{300}//' ./*
Run Code Online (Sandbox Code Playgroud)

或删除所有组合字符:

PERL_UNICODE=AS rename -n 's/\pM//g' ./*
Run Code Online (Sandbox Code Playgroud)

在那里,我们要perl考虑Arguments 和Stdio 流以 UTF-8 编码(请参阅与选项等效perldoc perlrun$PERL_UNICODEenv var的描述-C)并删除所有具有M方舟 Unicode 字符的字符p(or 的\pM缩写,请参阅详情)\p{Mark}\p{Combining_Mark}perldoc perluniprops

请注意,您应该能够列出该文件(在zsh):

ls -d $'a\u300'
Run Code Online (Sandbox Code Playgroud)

和:

ls -d $'\ue0'
Run Code Online (Sandbox Code Playgroud)

(并$'A\u300' and possibly $'\uc0À它的意思是不区分大小写),但是:

ls -d *A*
Run Code Online (Sandbox Code Playgroud)

并在以下外壳中zsh

ls -d *$'\ue0'*
ls -d *$'\xc3\xa0'*
Run Code Online (Sandbox Code Playgroud)

不会匹配它,因为 shell 列出当前目录的内容并对每个文件名应用模式,并且文件名被编码为a\u300不匹配的。

zsh但是和在MacOS只,壳内部与转换后的口音其预组合形式相结合的字母readdir(),仿佛将它们通过iconv -f UTF-8-MAC -t UTF-8它自己的内部zreaddir()包装器readdir()确实返回 U+00E0 而不是aU+0300它解释了为什么echo *à*在那里(而不是echo *a*)而不是在其他地方工作。

更改于 2014 年 6 月引入。有关详细信息,请参阅zsh 邮件列表上的讨论

问题的核心是用于用户输入的编码与用于在文件系统中存储(和列出)文件名的编码之间存在差异。这个问题在韩语中更严重,几乎每个字符都有一个预先组合和分解的形式,这解释了为什么 zsh 问题最初是由韩国人提出的。

所以zsh基本上修复了Apple在文件系统中选择分解形式的错误选择,因此可以使用其完成和globs,但不幸的是,这仅适用于zshls | grep à否则find . -name '*à*'仍然不起作用。