Como substituir espaços em todos os nomes de arquivos por sublinhado no Linux usando o shell script?


16

Eu tentei seguir o shell script que deve substituir os espaços de todos os nomes de arquivos xml

for xml_file in $(find $1 -name "* .xml" -type f);
do
 echo "removing spaces from XML file:" $xml_file
 mv "$xml_file" "${xml_file// /_}";
done

Suponha, eu tenho um arquivo xml com o nome xy z.xml, e ele fornece:

removing spaces from XML file: /home/krishna/test/xy
mv: cannot stat `/home/krishna/test/xy': No such file or directory
removing spaces from XML file: .xml
mv: cannot stat `z.xml': No such file or directory

Respostas:


26

Use isso com bash:

find $1 -name "* *.xml" -type f -print0 | \
  while read -d $'\0' f; do mv -v "$f" "${f// /_}"; done

findprocurará arquivos com um espaço no nome. Os nomes de arquivos serão impressos com um nullbyte ( -print0) como delimitador para também lidar com nomes de arquivos especiais. Em seguida, o readbuilt-in lê os nomes de arquivos delimitados pelo nullbyte e, finalmente,mv substitui os espaços por um sublinhado.

EDIT: Se você deseja remover os espaços nos diretórios também, é um pouco mais complicado. Os diretórios são renomeados e, em seguida, não são mais acessíveis pelo nome findencontrado. Tente o seguinte:

find -name "* *" -print0 | sort -rz | \
  while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done

A sort -rzinverte a ordem de arquivo, para que os arquivos mais profundos em uma pasta é o primeiro a se mover e a própria pasta será a última. Portanto, nunca há pastas renomeadas antes que todos os arquivos e pastas sejam renomeados dentro dela. O mvcomando no loop também é um pouco alterado. No nome do destino, removemos apenas os espaços no nome de base do arquivo, caso contrário, ele não estaria acessível.


Estou tentando substituir espaços com sublinhado em todo o diretório, mas está dando erro porque, depois de alterar o nome, esse diretório não está acessível.
precisa

@krishna Adicionei uma edição à minha resposta.
caos

1
@chaos wow, apenas correu estes dois em dois sistemas e funcionou como um encanto, alguns arquivos e diretórios não passando, mas é apenas alguns
somethingSomething

No macOS, precisamos especificar o diretório no comando find antes da opção -name find . -name "* *" -print0 | sort -rz | \ while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
Laszlo Pinter

16
  1. Usando rename

    find . -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;

    ou com $1

    find "$1" -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;
  2. Usando mv

    find . -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

    ou com $1

    find "$1" -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

Não sei por que, mas seu comando não está funcionando para mim. Não está mostrando nenhum erro e saída.
krishna

@krishna corrigido, sorry
AB

1
Renomear funcionou para mim. Soquinho!
Brian Piercy

1

Este é um método que encontrei ao enfrentar o mesmo problema:

for f in *; do mv "$f" `echo $f | tr ' ' '_'`; done

Eu estava escrevendo um arquivo de script bash para atualizar automaticamente meus certificados ssl.


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.