Como renomear arquivos em massa com codificação inválida ou substituir caracteres codificados inválidos em massa?

15

Eu tenho um servidor debian e estou hospedando músicas para uma estação de rádio na Internet. Tenho problemas com nomes e caminhos de arquivos porque muitos arquivos receberam uma codificação inválida, por exemplo:

./music/Bändname - Some Title - additional Info/B�ndname - 07 - This Title Is Cörtain, The EncÃding Not.mp3

Idealmente, gostaria de remover tudo o que não é letras A-Z/ a-zou números 0-9ou traço -/ sublinhado _... O resultado deve ser algo como isto:

./music/Bndname-SomeTitle-additionalInfo/Bndname-07-ThisTitleIsCrtain,TheEncdingNot.mp3

Como conseguir isso para um lote de muitos arquivos e diretórios?

Eu já vi essa pergunta semelhante: renomear em massa (ou exibir corretamente) arquivos com caracteres especiais

Mas isso apenas corrige a codificação, eu preferiria uma abordagem mais rigorosa, conforme descrito acima.

Afr
fonte

Respostas:

14

Você terá alguns problemas se quiser renomear arquivos e diretórios ao mesmo tempo. Renomear apenas um arquivo é fácil. Mas você deseja garantir que os diretórios também sejam renomeados. Você não pode simplesmente, mv Motörhead/Encöding Motorhead/Encodingpois Motorheadnão existirá no momento da ligação.

Portanto, precisamos de uma travessia profunda de todos os arquivos e pastas e renomear apenas o arquivo ou pasta atual. O seguinte funciona com o GNU finde o Bash 4.2.42 no meu OS X.

#!/usr/bin/env bash
find "$1" -depth -print0 | while IFS= read -r -d '' file; do
  d="$( dirname "$file" )"
  f="$( basename "$file" )"
  new="${f//[^a-zA-Z0-9\/\._\-]/}"
  if [ "$f" != "$new" ]      # if equal, name is already clean, so leave alone
  then
    if [ -e "$d/$new" ]
    then
      echo "Notice: \"$new\" and \"$f\" both exist in "$d":"
      ls -ld "$d/$new" "$d/$f"
    else
      echo mv "$file" "$d/$new"      # remove "echo" to actually rename things
    fi
  fi
done

Você pode alterar a regex usando new="${f//[\\\/\:\*\?\"<>|]/}"se desejar substituir algo que o Windows não possa manipular.

Salve este script como rename.sh, torne-o executável com chmod +x rename.sh. Então, chame assim rename.sh /some/path.

Certifique-se de resolver qualquer colisão de nome de arquivo (" Notice" anúncios).

Se você tiver certeza absoluta de que faz as substituições corretas, remova echoo script para renomear as coisas em vez de apenas imprimir o que faz.

Para segurança, recomendo testar isso em um pequeno subconjunto de arquivos primeiro.


Opções explicadas

Para explicar o que se passa aqui:

  • -depthgarantirá que os diretórios sejam recursivos em profundidade primeiro, para que possamos "acumular" tudo do final. Geralmente, findpercorre de maneira diferente (mas não a largura).
  • -print0garante que a findsaída seja delimitada por nulo, para que possamos lê-la read -d ''na filevariável Isso nos ajuda a lidar com todos os tipos de nomes de arquivos estranhos, incluindo aqueles com espaços e até novas linhas.
  • Obteremos o diretório do arquivo com dirname. Não se esqueça de sempre citar suas variáveis ​​corretamente, caso contrário, qualquer caminho com espaços ou caracteres brilhantes quebraria esse script.
  • Obteremos o nome do arquivo real (ou nome do diretório) com basename.
  • Em seguida, removemos qualquer caractere inválido do $fuso dos recursos de substituição de string do Bash. Inválido significa qualquer coisa que não seja uma letra maiúscula ou minúscula, um dígito, uma barra ( \/), um ponto ( \.), um sublinhado ou um hífen negativo.
  • Se $fjá estiver limpo (o nome limpo é idêntico ao nome atual), pule-o.
  • Se $newjá existir no diretório $d(por exemplo, você possui arquivos nomeados resumee résuméno mesmo diretório), emita um aviso. Você não deseja renomeá-lo porque, em alguns sistemas, mv foo foocausa um problema. De outra forma,
  • Finalmente renomeamos o arquivo original (ou diretório) para seu novo nome

Como isso funcionará apenas na hierarquia mais profunda, a renomeação Motörhead/Encödingpara Motorhead/Encodingé feita em duas etapas:

  1. mv Motörhead/Encöding Motörhead/Encoding
  2. mv Motörhead Motorhead

Isso garante que todas as substituições sejam feitas na ordem correta.


Arquivos de exemplo e execução de teste

Vamos assumir alguns arquivos em uma pasta base chamada test:

test
test/Motörhead
test/Motörhead/anöther_file.mp3
test/Motörhead/Encöding
test/Randöm
test/Täst
test/Täst/Töst
test/with space
test/with-hyphen.txt
test/work
test/work/resume
test/work/résumé
test/work/schedule

Aqui está a saída de uma execução no modo de depuração (com o echona frente do mv), ou seja, os comandos que seriam chamados e os avisos de colisão:

mv test/Motörhead/anöther_file.mp3 test/Motörhead/another_file.mp3
mv test/Motörhead/Encöding test/Motörhead/Encoding
mv test/Motörhead test/Motorhead
mv test/Randöm test/Random
mv test/Täst/Töst test/Täst/Tost
mv test/Täst test/Tast
mv test/with space test/withspace
Notice: "resume" and "résumé" both exist in test/work:
-rw-r—r--  …  …  test/work/resume
-rw-r—r--  …  …  test/work/résumé

Observe a ausência de mensagens para with-hyphen.txt, schedulee testem si.

slhck
fonte
1
Você pode adicionar lógica para lidar com o caso em que o destino do mvjá existe, o que pode acontecer (1) se você tiver arquivos que já estão limpos (resultando em mv foo foo) ou (2) se você tiver arquivos com o mesmo nome, exceto para os caracteres especiais (por exemplo, mv Encöding Encodingonde você já possui um Encodingarquivo além de Encöding).
Scott
Boa ideia, obrigado. Alguma sugestão específica sobre o que fazer nesse caso? Concedido - conseguir isso de maneira limpa e sã é mais difícil do que parece à primeira vista. Se você tiver algo, sinta-se à vontade para editar, é claro.
slhck
Não acredito que faça sentido pensar em lidar com as colisões automaticamente - apenas identifique-as para o usuário e deixe-as lidar com elas. Editei sua resposta, como você sugeriu.
Scott
+1 para usar o exemplo com "Encöding" Too much fön! :-)
Marcel
Depois de três anos, eu ainda volto aqui. tão útil! :-)
Afr
15

Eu sei que não é exatamente o que você queria, mas se você conhece a codificação original, talvez seja possível convmvalterar a codificação para UTF-8, o que deve corrigir a maioria dos problemas.

Isso funcionou para mim em uma pasta com alguns nomes de arquivos poloneses codificados inválidos:

convmv -f cp1250 -t utf8 -r .

Observe que esse comando não renomeia nada; Adicionar --notestopção para realmente renomear os arquivos.

mik01aj
fonte
1
Para quem tem um conjunto estático (ou não possui uma combinação diversificada de conjuntos de caracteres), a convmvopção é incrivelmente simples e perfeita. Para o OP, com uma infinidade de conjuntos de caracteres em potencial, isso poderia ser mesclado com a outra resposta, pois convmvparece saber quando ou quando não encontra o formato correto. Ao percorrer os charsets, via convmv --list, seria possível codificá-los adequadamente.
1
Com isso, quero dizer, se, como OP, executa um servidor Debian, certamente assumiríamos o UTF8 atualmente; nesse caso, podemos manter as letras originais. Eu tinha uma pasta com alguns caracteres nórdicos e usei: convmv -t utf8 --nfc -f iso-8859-1 --notest -r .- --nfcEra para estar em conformidade com o Linux antes do OS X mais ou menos, simplesmente digitar convmvabre as opções (úteis).
0

Eu sei, você perguntou sobre renomear.

Mas você pode evitar o problema facilmente usando software como o MusicBrainz Picard .

Ele é capaz de identificar músicas (impressões digitais de áudio), baixar todos os dados necessários (incluindo imagens de capa, quando disponíveis) do enorme banco de dados MusicBrainz e mover os arquivos para que sua coleção se encaixe no padrão desejado. Estou usando há anos e sempre funcionou perfeitamente com qualquer coisa, do cirílico ao árabe; e, é claro (pelo menos para scripts baseados em latim), ele também pode fazer a conversão para ASCII.

Com essa abordagem, não importa realmente o quão bagunçada / mal nomeada sua coleção realmente é, desde que os arquivos estejam legíveis e completos.

(Eu mencionei que é gratuito? Tanto na liberdade de expressão quanto na cerveja grátis? Tanto o software quanto o banco de dados ...?)

Alois Mahdal
fonte