Osx

如何在 macOS 上重命名帶有重音符號的文件名?

  • October 29, 2017

我正在嘗試重命名包含字元“à”的文件。

我執行以下操作:

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 個解決方案都完成了這項工作:

  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' *

如果您對這些解決方案中的任何一個都不滿意,請查看所選答案以找到有用的提示。

至少在 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建議考慮Arguments 和Stdio 流以 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不匹配的。

然而,僅在zshmacOS 上,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,但不幸的是,這只適用於zshls | grep à或者find . -name '*à*'仍然不起作用。

引用自:https://unix.stackexchange.com/questions/399927