Evite substituir espaços ao renomear arquivos

10

Estou tentando renomear arquivos como este:

for file in *;
do
mv -i "$file" "$(echo "$file" | sed -e 's/[^A-Za-z0-9._-]/_/g')";
done

Mas o sedcomando substitui todos os espaços com _.

Como posso editar o sedcomando para incluir espaços junto com os caracteres especificados? Eu tentei usar, \smas ele não funciona ...

EDIT:
Por exemplo: o arquivo trip: hilldeve ser renomeado:, trip_ hillmas o comando acima o faz trip__hill.

Zanna
fonte
Estou movendo alguns arquivos do linux para o Mac. Mas, por alguma razão, o sistema Mac não pode ler todos os nomes de arquivos, então estou tentando renomear meus arquivos. Adicionar um espaço ao comando acima não funciona. E você está correto: desejo substituir todos os caracteres por '_', exceto os especificados. E não sei como incluir o caractere de espaço.
Observe que estou tentando substituir todos os caracteres por '_', exceto os especificados. Não há um padrão específico para os arquivos que estão sendo renomeados, portanto, não posso usar este comando perl.

Respostas:

11

Não analise nomes de arquivos com sed! A saída de echo "$file"pode não ser confiável.

Use rename. Na 17.10, você precisa instalá-lo primeiro

sudo apt install rename

Então:

rename -n -- 's/[^-A-Za-z0-9_ .]/_/g' *

Notas

  • remova -napós o teste para renomear os arquivos
  • -- fim de opções, caso algum arquivo comece com -
  • [^-A-Za-z0-9_ .]caracteres que não queremos substituir - coloque o -primeiro ou o último para que não possa indicar um intervalo (é tratado literalmente nessas posições).
  • Os espaços podem ser incluídos na classe
  • . é tratado literalmente (em outros contextos regex, significa qualquer caractere e precisa ser escapado).

Isso também funciona em sed:

$ echo 'trip: hill' | sed 's/[^-A-Za-z0-9 _.]/_/g'
trip_ hill

Se eu adicionar um espaço ao final da sua versão, recebo um erro:

$ echo 'trip: hill' | sed -e 's/[^A-Za-z0-9._- ]/_/g'
sed: -e expression #1, char 22: Invalid range end

Mas com -no final, funciona:

$ echo 'trip: hill' | sed -e 's/[^A-Za-z0-9._ -]/_/g'
trip_ hill

Talvez a posição do hífen tenha causado seu problema quando você adicionou o espaço. Mas o conselho para não analisar nomes de arquivos permanece!

Zanna
fonte
Este comando funciona obrigado. Você também identificou claramente os erros no comando que usei.
2
Mais uma vez obrigado. Observe que não há necessidade de usar a barra '\' no caso de usar sed. Porque isso adiciona '\' à lista de caracteres ignorados.
2
@latach Isso é uma barra invertida, mas você está absolutamente certo. Depois de testar e procurar, descobri que isso .é literal em uma classe de caracteres. TIL!
Zanna
2

Você também pode usar o shell, a expansão de parâmetros do Bash pode fazer a substituição:

for f in ./* ; do
    mv "$f" "${f//[^-A-Za-z0-9._ ]/_}"
done

A barra dupla diz para substituir todas as correspondências, além disso, a sintaxe é direta.

ilkkachu
fonte