Em um sistema de arquivos em que os nomes de arquivos estão em UTF-8, tenho um arquivo com um nome com defeito; é exibido como D�sinstaller
:, nome real de acordo com zsh D$'\351'sinstaller
:, Latin1 para Désinstaller
, ele próprio um barbarismo francês para "desinstalação". O Zsh não combinaria com isso, [[ $file =~ '^.*$' ]]
mas sim com um brilho *
- esse é o comportamento que eu espero.
Agora, ainda espero encontrá-lo durante a execução find . -name '*'
- na verdade, nunca esperaria que um nome de arquivo falhasse neste teste. No entanto, com LANG=en_US.utf8
, o arquivo não aparece e eu tenho que definir LANG=C
(ou en_US
, ou ''
) para que ele funcione.
Pergunta: Qual é a implementação por trás e como eu poderia prever esse resultado?
Informações: Arch Linux 3.14.37-1-lts, find (GNU findutils) 4.4.2
convmv
em converter nomes de arquivos para utf-8?[[ $file =~ '^.*$' ]]
não usarrecode
o nome do arquivo, mas agora analisareiconvmv
se necessário. Obrigado.Respostas:
Essa é uma pegadinha muito legal. De uma rápida olhada no código fonte para a descoberta GNU, eu diria que isso se resume a como
fnmatch
se comporta em seqüências de bytes inválidas (pred_name_common
inpred.c
):Esse código testa o valor de retorno de
fnmatch
igualdade com 0, mas não verifica se há erros; isso resulta em qualquer erro relatado como "não corresponde".Foi sugerido, há muitos anos, alterar o comportamento dessa função libc para sempre retornar verdadeiro no
*
padrão, mesmo em nomes de arquivos quebrados, mas pelo que posso dizer, a ideia deve ter sido rejeitada (consulte o tópico a partir de https : //sourceware.org/ml/libc-hacker/2002-11/msg00071.html ):Como mencionado por Stéphane Chazelas em um comentário, e também no mesmo segmento de 2002, isso é inconsistente com a expansão glob realizada por shells, que não engasgam com caracteres inválidos. Talvez ainda mais intrigante seja o fato de que a reversão do teste corresponderá apenas aos arquivos que têm nomes quebrados (crie arquivos no bash com
touch $'D\351marrer' $'Touch\303\251' $'\346\227\245\346\234\254\350\252\236'
):Portanto, para responder sua pergunta, você poderia ter previsto isso conhecendo o comportamento do seu
fnmatch
neste caso e sabendo comofind
lida com o valor de retorno dessa função; você provavelmente não poderia ter descoberto apenas lendo a documentação.fonte
*
é que seria inconsistenteD*staller
.D*staller
coincidisse$'D\351sinstaller'
tão bem quanto na glob de todas as conchas que testei. Dado que o comportamento do GNU fnmatch não é consistente com o do shell GNU, eu diria que é um bug..
deve corresponder apenas a caracteres válidos na codificação - daí a minha expectativa de que.*
não corresponda a cadeias inválidas - mas não consigo encontrar uma especificação correspondente para a estrela brilhante.-name '*'
corresponde a todos os arquivos, incluindo nomes quebrados), então presumivelmente a versão do BSDfnmatch
, que não reivindica o desempenho POSIX.2, ao contrário da versão GNU, tem uma interpretação diferente e sem dúvida mais saudável do que deve ser feito em caracteres inválidos.A
-name
opção find usa a notação de correspondência de padrão de shell para executar o nome de arquivo correspondente.*
é um padrão que corresponde a vários caracteres , deve corresponder a uma sequência de zero ou mais caracteres.find
usa fnmatch para verificar a correspondência de padrões, para que você possa usar ltrace para verificar o resultado:Com
D\351sinstaller
,fnmatch
return-1
, indicou que não conseguiu corresponder. Um caractere válido comoሒaa
será correspondido.No seu caso, com
UTF-8
código de idioma,\351
é um caractere inválido, causando falha na correspondência de padrões.fonte
ltrace
. Eu sabiastrace
, masltrace
é novo para mim. Encantador!