Como renomear nomes de arquivos com acentos no macOS?

4

Estou tentando renomear arquivos que incluam o caractere "à".

Eu faço o seguinte:

rename -v 's/à/a/g' *

Mas mostra todos os arquivos como inalterados. O modo detalhado mostra a mesma coisa.

Eu tentei escapar com \ , mas sem sorte.

Como posso fazer a regex corresponder a esse tipo de caractere?

EDITAR

A saída de 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
    .

EDIT 2:

Saída de locale :

LANG=
LC_COLLATE="C"
LC_CTYPE="UTF-8"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=

SOLUÇÃO

Aqui está, em poucas palavras, o que funcionou. Todas as 3 soluções fizeram o trabalho:

  1. rename -nv $'s/a\xcc\x80/a/g' *
  2. %código%. (veja explicações na resposta escolhida)
  3. Mudando para PERL_UNICODE=AS rename -n 's/\pM//g' ./* , em vez do shell padrão do MacOS ( zsh ), meu comando original (sem necessidade de especificar caracteres combinados, como bash ) funcionou: a\u300 .

Se você não estiver satisfeito com qualquer uma dessas soluções, consulte a resposta escolhida para encontrar dicas úteis.

    
por lapin 23.10.2017 / 17:02

1 resposta

4

No macOS e com o sistema de arquivos HFS +, pelo menos, caracteres acentuados são codificados em sua forma decomposta, então à é codificado como a\u300 ( a seguido pelo combinando acento grave < href="https://en.wikipedia.org/wiki/Combining_character"> combinando caractere ) mesmo se você criou o arquivo com touch $'\ue0' (o formulário pré-composto (autônomo a com sotaque grave), causando todos os tipos de bugs (e sujeito de uma das famosas declarações de Linus Torvald ) como por seu pseudo insensibilidade de caixa.

Você notará que, se fizer isso:

touch à; echo ?

para listar os nomes dos arquivos feitos de um caractere, ele não retorna nada enquanto:

echo ??

ou

echo *a*

Retorna esse à (na verdade, ). E:

$ echo ?? | uconv -x name
\N{LATIN SMALL LETTER A}\N{COMBINING GRAVE ACCENT}\N{<control-000A>}

Então você precisaria:

rename $'s/a\u300/a/g' ./*

(assumindo zsh ou shell compatível). Ou usando especificando a codificação UTF-8 daquele caractere U + 0300 (0xcc 0x80) manualmente, para shells que suportam o ksh93 $'...' quotes, mas não zsh ' $'\u300' (como a versão antiga de bash encontrado no macOS):

rename $'s/a\xcc\x80/a/g' ./*

Ou deixe que perl interprete essas sequências \xcc\x80 diretamente:

rename 's/a\xcc\x80/a/g' ./*

Ou o caractere unicode:

PERL_UNICODE=AS rename 's/\x{300}//' ./*

Ou remova todos os caracteres combinados com:

PERL_UNICODE=AS rename -n 's/\pM//g' ./*

Lá, estamos dizendo que perl considera A rguments e S tdio streams são codificados em UTF-8 (consulte perldoc perlrun para obter uma descrição do $PERL_UNICODE env var equivalente ao -C option) e remova todos os caracteres que têm M ark Unicode p roperty ( \pM é a abreviação de \p{Mark} ou \p{Combining_Mark} , consulte perldoc perluniprops para obter detalhes)

Note que você deve poder listar esse arquivo (em zsh ) com os dois:

ls -d $'a\u300'

e:

ls -d $'\ue0'

(e $'A\u300' and possibly $'\uc0 para À , pois ele não diferencia maiúsculas de minúsculas), mas:

ls -d *A*

e em shells que não sejam zsh :

ls -d *$'\ue0'*
ls -d *$'\xc3\xa0'*

não corresponde, porque o shell lista o conteúdo do diretório atual e aplica o padrão a cada nome de arquivo, e o nome do arquivo é codificado como a\u300 , o que não coincide.

Em zsh , no entanto, e no macOS apenas, o shell converte internamente essas letras com acentos de combinação para seu formulário pré-composto em readdir() , como se estivesse passando-as por iconv -f UTF-8-MAC -t UTF-8 . Seu próprio wrapper zreaddir() interno em torno de readdir() não retorne U + 00E0 em vez de aU+0300 , o que explica por que echo *à* trabalha lá (e não echo *a* ) e não em outro lugar.

A alteração foi introduzida em junho de 2014. Consulte a discussão na lista de discussão zsh para obter mais detalhes .

O núcleo do problema é a discrepância entre a codificação usada na entrada do usuário e aquela usada para armazenar (e listar) nomes de arquivos no sistema de arquivos. O problema é muito pior em coreano, onde praticamente todos os personagens têm um formulário pré-composto e decomposto, o que explica por que a questão do zsh foi levantada inicialmente por uma pessoa coreana.

Portanto, zsh corrige a má escolha da Apple de forma decomposta no sistema de arquivos para que sua conclusão e globs possam ser usados, mas infelizmente isso se aplica apenas a zsh , ls | grep à ou find . -name '*à*' ainda não funcionará.

    
por 24.10.2017 / 11:41