granel renomear (ou exibir corretamente) arquivos com caracteres especiais

20

Eu tenho um monte de diretórios e subdiretórios que contêm arquivos com caracteres especiais, como este arquivo:

robbie@phil:~$ ls test�sktest.txt 
test?sktest.txt

Encontrar revela uma sequência de escape:

robbie@phil:~$ find test�sktest.txt -ls 
424512 4000 -rwxr--r-x   1 robbie   robbie    4091743 Jan 26 00:34 test3sktest.txt

A única razão pela qual eu posso digitar seus nomes no console é devido à conclusão da tabulação. Isso também significa que eu posso renomeá-los manualmente (e remover o caractere especial).

Eu configurei LC_ALL para UTF-8, o que não parece ajudar (também não em um novo shell):

robbie@phil:~$ echo $LC_ALL
en_US.UTF-8

Estou conectando à máquina usando o ssh do meu mac. É uma instalação do Ubuntu:

robbie@phil:~$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=7.10
DISTRIB_CODENAME=gutsy
DISTRIB_DESCRIPTION="Ubuntu 7.10"

Shell é Bash, TERM é definido como xterm-color.

Esses arquivos já existem há algum tempo e não foram criados usando essa instalação do Ubuntu. Então eu não sei o que as configurações de codificação do sistema costumavam ser.

Eu tentei as coisas ao longo das linhas:

find . -type f -ls | sed 's/[^a-zA-Z0-9]//g'

Mas não consigo encontrar uma solução que faça tudo o que eu quero:

  1. Identifica todos os arquivos que possuem caracteres indisplayable (o acima ignora muito)
  2. Para todos esses arquivos em uma árvore de diretórios (recursivamente), execute mv oldname newname
  3. Opcionalmente, a capacidade de transliterar caracteres especiais como ä para um (não obrigatório, mas seria incrível)

OR

  1. Exiba corretamente todos esses arquivos (e nenhum erro nos aplicativos ao tentar abri-los)

Eu tenho partes e partes, como iterar todos os arquivos e movê-los, mas identificar os arquivos e formatá-los corretamente para o comando mv parece ser a parte difícil.

Qualquer informação extra sobre por que eles não são exibidos corretamente ou como "adivinhar" a codificação correta também é bem-vinda. (Eu tentei convmv mas não parece fazer exatamente o que eu quero: link )

    
por RobbieV 26.01.2011 / 01:17

4 respostas

21

Acho que você vê esse caractere inválido porque o nome contém uma sequência de bytes que não é válida UTF-8. Nomes de arquivos em sistemas de arquivos unix típicos (incluindo o seu) são sequências de bytes, e cabe aos aplicativos decidir qual codificação usar. Atualmente, há uma tendência a usar o UTF-8, mas não é universal, especialmente em locais que nunca poderiam viver com ASCII simples e usavam outras codificações desde antes da existência do UTF-8.

Teste LC_CTYPE=en_US.iso88591 ls para ver se o nome do arquivo faz sentido em ISO-8859-1 (latim-1). Se isso não acontecer, tente outras localidades. Observe que somente a configuração LC_CTYPE locale é importante aqui.

Em uma localidade UTF-8, o comando a seguir mostrará todos os arquivos cujo nome não é válido UTF-8:

grep-invalid-utf8 () {
  perl -l -ne '/^([
find | grep-invalid-utf8 | recode latin1..utf8
find | grep-invalid-utf8 | iconv -f latin1 -t utf8
0-7]|[0-7][0-7]|[0-7][0-7]{2}|[0-7][0-7]{3}|[0-3][0-7]{4}|[4-5][0-7]{5})*$/ or print' } find | grep-invalid-utf8

Você pode verificar se eles fazem mais sentido em outro local com recode ou < href="http://manpages.ubuntu.com/manpages/lucid/man1/iconv.1.html"> íconev :

find | grep-invalid-utf8 |
rename 'BEGIN {binmode STDIN, ":encoding(latin1)"; use Encode;}
        $_=encode("utf8", $_)'

Depois de determinar que vários nomes de arquivos estão em uma determinada codificação (por exemplo, latin1), uma maneira de renomeá-los é

grep-invalid-utf8 () {
  perl -l -ne '/^([
find | grep-invalid-utf8 | recode latin1..utf8
find | grep-invalid-utf8 | iconv -f latin1 -t utf8
0-7]|[0-7][0-7]|[0-7][0-7]{2}|[0-7][0-7]{3}|[0-3][0-7]{4}|[4-5][0-7]{5})*$/ or print' } find | grep-invalid-utf8

Isso usa o comando renomear do perl disponível no Debian e no Ubuntu. Você pode passar -n para mostrar o que estaria fazendo sem realmente renomear os arquivos.

    
por 26.01.2011 / 01:54
1

Eu sei que esta é uma pergunta antiga, mas eu tenho procurado a solução toda a noite toda. Eu encontrei algumas dicas úteis, mas eles não fizeram exatamente o que eu precisava, então eu tive que misturar e combinar alguns para obter o resultado correto que eu estava procurando

para simplesmente remover caracteres especiais e substituí-los por um ponto (.)

for f in *.txt; do mv "$f" 'echo $f | sed "s/[^a-zA-Z0-9.]/./g"'; done

para usar em um cronjob Eu fiz o seguinte para executar cada minuto

*/1 * * * * cd /path/to/files/ && for f in *.txt; do mv "$f" 'echo $f | sed "s/[^a-zA-Z0-9.]/./g"'; done >/dev/null 2>&1

Espero que alguém ache isso útil, pois fez meu dia:)

    
por 27.05.2016 / 09:01
0

Agora, quando você sabe qual codificação é usada para os nomes de arquivos no terminal remoto ("latin1" - de acordo com os comentários da primeira resposta), você também pode seguir o segundo caminho - - execute um termninal local e ssh de tal forma que os nomes dos arquivos remotos sejam exibidos corretamente (ao invés da primeira maneira: renomeie-os) .

Assim como eu , você poderia iniciar um terminal localmente que funcionaria nessa codificação especial, talvez, assim :

LC_ALL = en_US.latin1 xvt &

xvt significa seu programa de terminal.

Talvez, a localidade existente seja chamada en_US.iso88591 e não en_US.latin1 , como assumi.

    
por 25.11.2011 / 19:17
0

Isso não atende aos requisitos em massa, mas acabei de ter um problema semelhante em que eu tinha várias versões de um arquivo com nomes semelhantes que diferiam apenas por um único caractere estranho. Infelizmente, isso significava que eu não poderia renomear os infratores usando o truque de curinga que eu costumo usar.

No final, usei o Filezilla para conectar-me como um cliente SFTP, naveguei até os arquivos e os renomei usando a GUI. O Filezilla lidou bem com os caracteres desonestos.

Espero que isso ajude alguém: -)

    
por 09.01.2013 / 12:04