Como remover caracteres inválidos dos nomes de arquivos?


47

Tenho arquivos com caracteres inválidos como estes

009_-_�%86ndringshåndtering.html

É Æonde algo deu errado no nome do arquivo.

Existe uma maneira de remover todos os caracteres inválidos?

ou poderia trser usado de alguma forma?

echo "009_-_�%86ndringshåndtering.html" | tr ???

5
Os caracteres provavelmente não são "inválidos"; caso contrário, o sistema de arquivos não os armazenará (a menos que você faça algo realmente desagradável com o FS). Você tentou alterar seu código do idioma (por exemplo, para UTF8) para exibir os nomes corretamente?
James O'Gorman

Respostas:


41

Uma maneira seria com sed:

mv 'file' $(echo 'file' | sed -e 's/[^A-Za-z0-9._-]/_/g')

Substitua filepelo seu nome do arquivo, é claro. Isso substituirá qualquer coisa que não seja uma letra, número, ponto, sublinhado ou traço por um sublinhado. Você pode adicionar ou remover caracteres para manter o que quiser e / ou alterar o caractere de substituição para qualquer outra coisa, ou absolutamente nada.


4
Eu usei:f='file'; mv 'file' ${f//[^A-Za-z0-9._-]/_}
Louis

11
Procure a melhor solução por H. Hess abaixo ... (e meu comentário engraçado ao lado :))
Jan Sila

31

Suponho que você esteja na caixa Linux e os arquivos foram criados em uma caixa Windows. O Linux usa UTF-8 como a codificação de caracteres para nomes de arquivos, enquanto o Windows usa outra coisa. Eu acho que essa é a causa do problema.

Eu usaria "convmv". Esta é uma ferramenta que pode converter nomes de arquivos de uma codificação de caracteres para outra. Para a Europa Ocidental, um destes normalmente funciona:

convmv -r -f windows-1252 -t UTF-8 .
convmv -r -f ISO-8859-1 -t UTF-8 .
convmv -r -f cp-850 -t UTF-8 .

Se você precisar instalá-lo em um Linux baseado no Debian, poderá fazê-lo executando:

sudo apt-get install convmv

Funciona sempre para mim e recupera o nome do arquivo original.

Fonte: LeaseWebLabs


11
isso parece promissor, mas alguma idéia de como saber qual é a codificação? Eu tenho um diretório chamado Save the current file in Word 97-2004 format\sco.workflowque foi criado no meu Mac (via Microsoft Office) e as codificações acima não têm efeito.
Sridhar Sarnobat

Vale ressaltar que, por padrão, o convmv é executado no modo "teste", onde apenas executa uma execução a seco e informa quais arquivos ele moveria. Em seguida, ele será solicitado para executá-lo novamente com a --notestopção de renomear os arquivos.
Kenny Rasschaert 28/01

16

Suponho que você queira atravessar o sistema de arquivos e corrigir todos esses arquivos?

Aqui está o jeito que eu faria

find /path/to/files -type f -print0 | \
perl -n0e '$new = $_; if($new =~ s/[^[:ascii:]]/_/g) {
  print("Renaming $_ to $new\n"); rename($_, $new);
}'

Isso encontraria todos os arquivos com caracteres não-ascii e os substituiria por sublinhados ( _). Tenha cuidado, porém, se um arquivo com o novo nome já existir, ele será sobrescrito. O script pode ser modificado para verificar esse caso, mas não o coloquei para mantê-lo simples.


13

As respostas a seguir em https://stackoverflow.com/questions/2124010/grep-regex-to-match-non-ascii-characters , você pode usar:

rename 's/[^\x00-\x7F]//g' *

onde *corresponde aos arquivos que você deseja renomear. Se você quiser fazer isso em vários diretórios, poderá fazer algo como:

find . -exec rename 's/[^\x00-\x7F]//g' "{}" \;

Você pode usar o argumento -n para renameexecutar uma execução a seco e ver o que seria alterado, sem alterá-lo.


Existe uma maneira de modificar isso para manter caracteres estrangeiros como ü e ä, por exemplo?
Elder Geek

Apenas o segundo funcionou para mim. Tudo estava no mesmo diretório, então não tenho certeza de qual é a diferença ..?
Shautieh

11
@ Shautieh: o -n interrompe a execução. Vou esclarecer a resposta.
naught101

renomear pode ser lento ao lidar com muitos arquivos. Se você quiser acelerar isso, empurre a verificação para encontrar. Não tenho certeza de como fazer isso.
isaaclw 10/09

13

Eu recuperei alguns arquivos japoneses com nomes de arquivos quebrados de um pendrive quebrado e as soluções acima não funcionaram para mim.

Eu recomendo o pacote de desintoxicação:

O utilitário de desintoxicação renomeia os arquivos para facilitar o trabalho. Remove espaços e outros aborrecimentos. Também converterá ou limpará caracteres Latin-1 (ISO 8859-1) codificados em ASCII de 8 bits, caracteres Unicode codificados em UTF-8 e caracteres de escape CGI.

Exemplo de uso:

detox -r -v /path/to/your/files
-r Recursar em subdiretórios
-v Seja detalhado sobre quais arquivos estão sendo renomeados 
-n Pode ser usado para uma execução a seco (apenas mostre o que seria alterado)

2
Isso deve ser muito maior, peço a todos que dêem uma olhada detoxantes de essencialmente reinventar a roda. Se você olhar a página de manual, verá que ela cobre todas as outras soluções propostas aqui devido à sua flexibilidade.
emk2203

Ezequiel 25:17 - Bem-aventurado aquele que, em nome da caridade e do bem, vota esta solução, pois ele é verdadeiramente o guardador de seu irmão e o descobridor de crianças perdidas.
Jan Sila

Sem querer, o caminho não pode ser '.' no debian. Se você usar um '.' não encontra nada.
isaaclw 10/09

Gostaria de saber se realmente funciona, parece remover / substituir caracteres chineses, por exemplo 的节奏啊, mas esses caracteres são um nome de arquivo válido.
皞 皞 11/09

5

Esse script de shell limpa um diretório recursivamente, para tornar os arquivos portáveis ​​entre Linux / Windows e FAT / NTFS / exFAT. Ele remove os caracteres de controle /:*?"<>\|e alguns nomes reservados do Windows, como COM0.

sanitize() {
  shopt -s extglob;

  filename=$(basename "$1")
  directory=$(dirname "$1")

  filename_clean=$(echo "$filename" | sed -e 's/[\\/:\*\?"<>\|\x01-\x1F\x7F]//g' -e 's/^\(nul\|prn\|con\|lpt[0-9]\|com[0-9]\|aux\)\(\.\|$\)//i' -e 's/^\.*$//' -e 's/^$/NONAME/')

  if (test "$filename" != "$filename_clean")
  then
    mv -v "$1" "$directory/$filename_clean"
  fi
}

export -f sanitize

sanitize_dir() {
  find "$1" -depth -exec bash -c 'sanitize "$0"' {} \;
}

sanitize_dir '/path/to/somewhere'

O Linux é menos restritivo em teoria ( /e \0é estritamente proibido em nomes de arquivos), mas na prática vários caracteres interferem nos comandos bash (como *...), portanto, eles também devem ser evitados nos nomes de arquivos.

Ótimas fontes para restrições de nomes de arquivos:


11
É o que eu procuro! mas adicione aspas para dar suporte a diretórios com espaços, encontre "$ 1" -thp -exec bash -c 'sanitize "$ 0"' {} \;
mmv-ru


0

Eu uso esse recurso para remover caracteres inválidos nos arquivos de legenda:

for f in *.srt; do nf=$(echo "$f" |sed -e 's/[^A-Za-z0-9.-]/./g;s/\.\.\././g;s/\.\././g'); test "$f" != "$nf" && mv "$f" "$nf" && echo "$nf"; done
  1. Processe apenas arquivos * .srt (* pode ser usado no lugar de * .srt para processar todos os arquivos)
  2. Remove todos os outros caracteres, exceto as letras A-Za-z, números 0-9, pontos "." E traços "-"
  3. Remove possíveis períodos duplos ou triplos
  4. Verifica se o nome do arquivo precisa ser alterado
  5. Se verdadeiro, ele renomeia o arquivo com o comando mv e emite as alterações feitas com o comando echo

Ele trabalha para normalizar os nomes de diretório de filmes:

for f in */; do nf=$(echo "$f" |sed -e 's/[^A-Za-z0-9.]/./g' -e 's/\.\.\././g' -e 's/\.\././g' -e 's/\.*$//'); test "$f" != "$nf" && mv "$f" "$nf" && echo "$nf"; done

Mesmas etapas acima, mas eu adicionei mais um comando sed para remover um ponto no final do diretório

X-Men Days of Future Past (2014) [1080p]
Modificado para:
X-Men.Days.of.Future.Past.2014.1080p


-2

para arquivo em *; do mv "$ file" $ (eco "$ file" | sed -e 's / [^ A-Za-z0-9. -] / / g'); feito &


2
Você deve explicar o que seu código faz e usar a formatação adequada. Seu código pode fazer com que os arquivos sejam excluídos, introduzindo colisões nos nomes. E executar a coisa toda em segundo plano é meio bobo.
kasperd
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.