Comment remplacer les espaces dans tous les noms de fichiers par un soulignement sous Linux en utilisant un script shell?

17

J'ai essayé de suivre le script shell qui devrait remplacer les espaces de tous les noms de fichiers 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

Supposons que j'ai un fichier xml avec le nom xy z.xml, puis il donne:

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
krishna
la source

Réponses:

28

Utilisez-le avec bash:

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

findrecherchera les fichiers avec un espace dans le nom. Les noms de fichiers seront imprimés avec un nullbyte ( -print0) comme délimiteur pour gérer également les noms de fichiers spéciaux. Ensuite, la fonction readintégrée lit les noms de fichiers délimités par le nullbyte et mvremplace finalement les espaces par un trait de soulignement.

EDIT: Si vous souhaitez également supprimer les espaces dans les répertoires, c'est un peu plus compliqué. Les répertoires sont renommés et ne sont plus accessibles par les recherches de nom find. Essaye ça:

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

L' sort -rzinverse l'ordre des fichiers, de sorte que les fichiers les plus profonds d'un dossier soient les premiers à se déplacer et que le dossier lui-même sera le dernier. Ainsi, il n'y a jamais de dossiers renommés avant que tous les fichiers et dossiers ne soient renommés à l'intérieur. La mvcommande dans la boucle est également un peu modifiée. Dans le nom cible, nous supprimons uniquement les espaces dans le nom de base du fichier, sinon il ne serait pas accessible.

le chaos
la source
J'essaie de remplacer les espaces par un trait de soulignement dans tous les répertoires mais cela donne une erreur car après avoir changé de nom, ce répertoire n'est pas accessible.
krishna
@krishna J'ai ajouté une modification à ma réponse.
chaos
1
@chaos wow, juste exécuté ces deux sur deux systèmes et cela a fonctionné comme un charme, peu de fichiers et de répertoires ne passent pas mais ce n'est que quelques
quelque chose Quelque chose
Sur macOS, nous devons spécifier le répertoire dans la commande find avant l'option -name find . -name "* *" -print0 | sort -rz | \ while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
Laszlo Pinter
17
  1. En utilisant rename

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

    ou avec $1

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

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

    ou avec $1

    find "$1" -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;
UN B
la source
Je ne sais pas pourquoi mais votre commande donnée ne fonctionne pas pour moi. Il ne montre aucune erreur et sortie.
krishna
@krishna corrigé, désolé
AB
1
Renommer a fonctionné pour moi. Fistbump!
Brian Piercy
1

C'est une méthode que j'ai trouvée face au même problème:

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

J'écrivais un fichier de script bash pour mettre à jour automatiquement mes certificats SSL.

NekoMisaki
la source
1

Utilisation rename:

rename 's/\s/_/g' ./*.xml

Pas besoin de find:)

Jan Werkhoven
la source
1
ajoutez le g de fin au regex et cela fonctionne parfaitement. 's / \ s / _ / g'
jbrahy
Bon conseil, merci :)
Jan Werkhoven