111 votes

Renommer des fichiers par lots avec Bash

Comment Bash peut-il renommer une série de paquets pour supprimer leur numéro de version ? J'ai joué avec les deux méthodes expr y %% en vain.

Ejemplos:

Xft2-2.1.13.pkg devient Xft2.pkg

jasper-1.900.1.pkg devient jasper.pkg

xorg-libXrandr-1.2.3.pkg devient xorg-libXrandr.pkg

1 votes

J'ai l'intention de l'utiliser régulièrement, comme un script à écrire une fois pour toutes. Tout système que j'utiliserai aura bash dessus, donc je n'ai pas peur des bashismes qui sont très pratiques.

0 votes

Plus généralement, voir aussi stackoverflow.com/questions/28725333/

203voto

richq Points 29694

Vous pourriez utiliser la fonction d'expansion des paramètres de bash

for i in ./*.pkg ; do mv "$i" "${i/-[0-9.]*.pkg/.pkg}" ; done

Les guillemets sont nécessaires pour les noms de fichiers contenant des espaces.

1 votes

Je l'aime aussi, mais il utilise des fonctionnalités spécifiques à la base... Je ne les utilise normalement pas en faveur de sh "standard".

2 votes

Pour des trucs interactifs d'une ligne, j'utilise toujours cette méthode au lieu de sed-fu. Si c'était un script, yep, éviter les bashismes.

0 votes

Un problème que j'ai trouvé avec le code : Que se passe-t-il si les fichiers ont déjà été renommés et que je l'exécute à nouveau ? J'obtiens des avertissements si j'essaie de me déplacer dans un sous-répertoire de lui-même.

36voto

Diomidis Spinellis Points 8417

Si tous les fichiers sont dans le même répertoire, la séquence

ls | 
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' | 
sh

fera votre travail. Le site sed créera une séquence de mv que vous pouvez ensuite introduire dans le shell. Il est préférable d'exécuter d'abord le pipeline sans la terminaison | sh afin de vérifier que la commande fait ce que vous voulez.

Pour effectuer une récursion dans plusieurs répertoires, utilisez quelque chose comme

find . -type f |
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' |
sh

Notez que dans sed la séquence de regroupement des expressions régulières est constituée de parenthèses précédées d'une barre oblique inverse, \( y \) plutôt que des parenthèses simples ( y ) .

0 votes

Pardonnez ma naïveté, mais le fait d'échapper les parenthèses avec des antislashes ne les ferait-il pas traiter comme des caractères littéraux ?

2 votes

Dans sed, la séquence de regroupement des expressions régulières est (, plutôt qu'une simple parenthèse.

0 votes

N'a pas fonctionné pour moi, je serais heureux d'avoir votre aide.... Le suffixe du fichier FROM est ajouté au fichier TO : $find . -type d | sed -n 's/(.*)\/(.*)anysoftkeyboard(.*)/mv " \1\ / \2anysoftkeyboard\3 " " \1\ / \2effectedkeyboard\3 "/p'|sh >>>>>>>OUTPUT>>>> mv : rename ./base/src/main/java/com/anysoftkeyboard/base/dictionaries to ./base/src/main/java/com/effectedkeyboard/base/dictionaries/dictionaries : Aucun fichier ou répertoire de ce type

11voto

Diego Sevilla Points 17274

Je vais faire quelque chose comme ça :

for file in *.pkg ; do
    mv $file $(echo $file | rev | cut -f2- -d- | rev).pkg
done

supposant que tous vos fichiers sont dans le répertoire courant. Si ce n'est pas le cas, essayez d'utiliser find comme conseillé ci-dessus par Javier.

EDIT : De plus, cette version n'utilise pas de fonctionnalités spécifiques à bash, comme d'autres ci-dessus, ce qui vous conduit à une plus grande portabilité.

0 votes

Ils sont tous dans le même répertoire. Que pensez-vous de la réponse de rq ?

0 votes

J'aime ne pas utiliser de fonctionnalités spécifiques à la base, mais plutôt des sh standards.

1 votes

J'ai supposé que c'était pour un renommage rapide, pas pour écrire la prochaine génération d'application d'entreprise portable et multiplateforme ;-)

3voto

Javier Points 33134

Meilleure utilisation sed pour ça, quelque chose comme :

find . -type f -name "*.pkg" |
 sed -e 's/((.*)-[0-9.]*\.pkg)/\1 \2.pkg/g' |
 while read nameA nameB; do
    mv $nameA $nameB;
 done

L'élaboration de l'expression régulière est laissée à l'appréciation de chacun (tout comme le traitement des noms de fichiers comportant des espaces).

0 votes

Merci : Les espaces ne sont pas utilisés dans les noms.

1voto

Steve B. Points 23227

Cela semble fonctionner en supposant que

  • tout se termine par $pkg
  • vos numéros de version commencent toujours par un "-".

enlevez le .pkg, puis enlevez -

for x in $(ls); do echo $x $(echo $x | sed 's/\.pkg//g' | sed 's/-.*//g').pkg; done

0 votes

Certains paquets ont un trait d'union dans leur nom (voir le troisième exemple). Cela a-t-il un impact sur votre code ?

1 votes

Vous pouvez exécuter plusieurs expressions sed en utilisant -e . Par exemple sed -e 's/\.pkg//g' -e 's/-.*//g' .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X