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
A descoberta 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 test\323sktest.txt
A única razão pela qual posso digitar seus nomes no console é por causa do preenchimento de guias. Isso também significa que eu posso renomeá-los manualmente (e remover o caractere especial).
Eu configurei LC_ALL para UTF-8, o que parece não ajudar (também não em um novo shell):
robbie@phil:~$ echo $LC_ALL
en_US.UTF-8
Estou conectando à máquina usando 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 está definido como xterm-color.
Esses arquivos já estão lá há um bom tempo e não foram criados usando essa instalação do Ubuntu. Portanto, não sei quais eram as configurações de codificação do sistema.
Eu tentei as coisas ao longo das linhas de:
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:
- Identifique todos os arquivos que possuem caracteres não exibidos (o item acima ignora demais)
- Para todos esses arquivos em uma árvore de diretórios (recursivamente), execute mv oldname newname
- Opcionalmente, a capacidade de transliterar caracteres especiais como ä para a (não necessário, mas seria incrível)
OU
- Exiba corretamente todos esses arquivos (e nenhum erro nos aplicativos ao tentar abri-los)
Eu tenho bits e partes, como iterar sobre todos os arquivos e movê-los, mas identificar os arquivos e formatá-los corretamente para o comando mv parece ser a parte mais 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 o convmv, mas parece não fazer exatamente o que eu quero: http://j3e.de/linux/convmv/ )
Respostas:
Eu 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. Os nomes de arquivos em sistemas de arquivos unix típicos (incluindo o seu) são cadeias de bytes, e cabe aos aplicativos decidir qual codificação usar. Atualmente, existe uma tendência para 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.Tente
LC_CTYPE=en_US.iso88591 ls
ver se o nome do arquivo faz sentido na ISO-8859-1 (latin-1). Caso contrário, tente outros locais. Observe que apenas aLC_CTYPE
configuração de localidade é importante aqui.Em um código de idioma UTF-8, o comando a seguir mostra todos os arquivos cujo nome não é UTF-8 válido:
Você pode verificar se eles fazem mais sentido em outro local com recode ou iconv :
Depois de determinar que vários nomes de arquivos estão em uma determinada codificação (por exemplo, latin1), uma maneira de renomeá-los é
Isso usa o comando perl rename disponível no Debian e Ubuntu. Você pode passá-lo
-n
para mostrar o que faria sem realmente renomear os arquivos.fonte
grep [^[:print:]]
procurar caracteres não imprimíveis. Mas acabei de testar com o GNU grep e as sequências UTF-8 inválidas não são capturadas[^[:print:]]
(o que faz sentido, pois não são caracteres imprimíveis, nem caracteres). Eu editei minha postagem com uma maneira mais longa de grepping linhas com seqüências utf8 inválidas. Observe que também fixei a direção dos exemplosrecode
eiconv
.Sei que essa é uma pergunta antiga, mas tenho procurado a noite toda por uma solução semelhante. Encontrei algumas dicas úteis, mas elas não fizeram exatamente o que eu precisava, então tive que misturar e combinar algumas para obter o resultado correto que estava procurando.
para simplesmente remover caracteres especiais e substituí-los por um ponto (.)
para usar em um cronjob eu fiz o seguinte para executar a cada minuto
Espero que alguém ache isso útil, pois fez o meu dia :)
fonte
`…`
para$(…)
- veja isto , isto e isto . (2) Você deve sempre citar as referências de variáveis do shell (por exemplo,"$f"
) a menos que tenha um bom motivo para não fazê-lo e tenha certeza de que sabe o que está fazendo. Isso se aplica mesmo aecho "$f" | sed …
. Também se aplica a toda a expressão$(…)
(ou`…`
); ou seja,mv "$f" "$(echo "$f" | sed "…")"
. ... (continua)mv
--
"$f" …
-
Agora, quando você souber qual codificação é usada para os nomes de arquivos na extremidade remota ("latin1" - de acordo com os comentários da primeira resposta), você também poderá seguir o segundo caminho - execute um termninal local e ssh dessa maneira maneira como os nomes de arquivos remotos são exibidos corretamente (em vez da primeira maneira: renomeie-os) .
Como eu , você poderia iniciar um terminal localmente que funcionaria nessa codificação especial, talvez, assim:
LC_ALL = pt_BR.latin1 xvt &
xvt
representa o seu programa de terminal.Talvez o local existente seja chamado
en_US.iso88591
, e nãoen_US.latin1
, como eu assumi.fonte
Isso não atende aos requisitos em massa, mas acabei de ter um problema semelhante em que havia 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 podia renomear os infratores usando o truque curinga que costumo usar.
No final, usei o Filezilla para conectar-se como um cliente SFTP, naveguei nos arquivos e os renomeei usando a GUI. O Filezilla lidou muito bem com os caracteres desonestos.
fonte