如何在 macOS 上重命名帶有重音符號的文件名?
我正在嘗試重命名包含字元“à”的文件。
我執行以下操作:
rename -v 's/à/a/g' *
但它將所有文件顯示為未更改。詳細模式顯示相同的內容。
我試圖逃跑,
\
但沒有運氣。如何使正則表達式匹配這種類型的字元?
編輯
的輸出
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 .
編輯 2:
輸出
locale
:LANG= LC_COLLATE="C" LC_CTYPE="UTF-8" LC_MESSAGES="C" LC_MONETARY="C" LC_NUMERIC="C" LC_TIME="C" LC_ALL=
解決方案
簡而言之,這是有效的。所有 3 個解決方案都完成了這項工作:
rename -nv $'s/a\xcc\x80/a/g' *
PERL_UNICODE=AS rename -n 's/\pM//g' ./*
. (請參閱所選答案中的解釋)- 切換到
zsh
,而不是 MacOS 的預設 Shell (bash
),然後我的原始命令(無需指定組合字元,例如a\u300
)起作用:rename -v 's/à/a/g' *
。如果您對這些解決方案中的任何一個都不滿意,請查看所選答案以找到有用的提示。
至少在 macOS 和 HFS+ 文件系統上,重音字元以其分解形式
à
編碼,因此即使您使用a\u300
(a
預組合形式 (獨立帶有嚴重的口音),導致各種錯誤(以及Linus Torvald 著名的咆哮之一的主題),比如它的偽不區分大小寫。touch $'\ue0'``a
你會注意到,如果你這樣做:
touch à; echo ?
要列出由一個字元組成的文件名,它不會返回任何內容:
echo ??
或者
echo *a*
確實返回
à
(實際上à
)。和:$ echo ?? | uconv -x name \N{LATIN SMALL LETTER A}\N{COMBINING GRAVE ACCENT}\N{<control-000A>}
所以你需要:
rename $'s/a\u300/a/g' ./*
(假設
zsh
或兼容的外殼)。或者使用手動指定 U+0300 字元 (0xcc 0x80) 的 UTF-8 編碼,用於支持 ksh93$'...'
引號但不支持zsh
‘s的 shell(如macOS 上$'\u300'
的古代版本):bash
rename $'s/a\xcc\x80/a/g' ./*
或者讓我們直接
perl
解釋這些\xcc\x80
序列:rename 's/a\xcc\x80/a/g' ./*
或 Unicode 字元:
PERL_UNICODE=AS rename 's/\x{300}//' ./*
或刪除所有組合字元:
PERL_UNICODE=AS rename -n 's/\pM//g' ./*
在那裡,我們
perl
建議考慮A
rguments 和S
tdio 流以 UTF-8 編碼(有關與該選項等效的 env varperldoc perlrun
的描述,請參閱)並刪除所有具有ark Unicode roperty 的字元(是or的縮寫,請參閱詳情)$PERL_UNICODE``-C``M``p``\pM``\p{Mark}``\p{Combining_Mark}``perldoc perluniprops
請注意,您應該能夠同時列出該文件(在 中
zsh
):ls -d $'a\u300'
和:
ls -d $'\ue0'
(並且
$'A\u300' and possibly $'\uc0
因為À
它不區分大小寫),但是:ls -d *A*
並在以下貝殼中
zsh
:ls -d *$'\ue0'* ls -d *$'\xc3\xa0'*
不會匹配它,因為 shell 列出了目前目錄的內容並將模式應用於每個文件名,並且文件名被編碼為
a\u300
不匹配的。然而,僅在
zsh
macOS 上,shell 在內部將這些帶有組合重音符號的字母轉換為其預先組合的形式,readdir()
就好像它們通過iconv -f UTF-8-MAC -t UTF-8
. 它自己的內部zreaddir()
包裝器readdir()
確實返回 U+00E0 而不是aU+0300
解釋為什麼echo *à*
在那裡(而不是echo *a*
)而不是其他地方工作。該更改於 2014 年 6 月引入。有關更多詳細資訊,請參閱 zsh 郵件列表上的討論。
問題的核心是用於使用者輸入的編碼與用於在文件系統中儲存(和列出)文件名的編碼之間的差異。這個問題在韓語中要嚴重得多,幾乎每個字元都有一個預先組合和分解的形式,這解釋了為什麼 zsh 問題最初是由韓國人提出的。
所以
zsh
基本上修復了Apple在文件系統中對分解形式的糟糕選擇,因此可以使用它的完成和glob,但不幸的是,這只適用於zsh
,ls | grep à
或者find . -name '*à*'
仍然不起作用。