SED Renuméroter les noms d'une liste de fichiers

Bonjour,
je ne suis pas un aficionados de sed, mais avec une pratique de vim je m’y retrouve.

J’ai résolu la question posée dans le titre ainsi, mais certains d’entre vous auront certainement mieux à proposer.

Il s’agit de renuméroter une série de fichiers dont le nom est sous la forme:

200_nomIdentique.xxx à 220_nomIdentique.xxx

[Correctif, voir plus bas: les noms ne sont pas identiques]

en ajoutant «1» au nombre initial.

Voici ma solution:
La ligne de commande:
—————————————————————

for i in {220..200} ; do j=$((i + 1)); F=$(echo ${i}*) ; f=$(echo "$F"  | sed s/$i/$j/) ; echo "$F → $f" ; mv "$F" "$f" ; done

Explication:
—————————————————————

1 for i in {220..200} ;             # Les numéros des noms de fichiers à remplacer
2 do 
3  j=$((i + 1));                   # nouvelle numérotation ( j = i+1 )
4  F=$(echo ${i}*) ;               # nom du fichier initial (i)
5  f=$(echo "$F"  | sed s/$i/$j/); # nom du fichier final ( s/$i/$j ) 
6  echo "$F → $f" ;                # affichage pour vérifier
7  mv "$F" "$f" ;                  # remplacement effectif
8 done

(On remplace la ligne 6 par la ligne 7 si la ligne 6 affiche le résultat voulu.)

Numérotation autre qu’en préfixe:
——————————————————
Si le numéro est le seul nombre de la série (ici 200 à 220) dans les noms de tous les fichiers du répertoire, alors on peut faire ma même chose en ne modifiant que les jockers de la ligne 4.

je ne pense pas que sed soit l’utilitaire le plus adapté pour ça.
peut être regarder du coté de rename ?

Bonjour

Pas besoin de sed pour faire ce travail,
bash a déjà tout ce qu’il faut pour ça :

Pour voir comment fonctionne l’extraction d’une sous-chaîne en fonction d’un caractère séparateur,
lance successivement les quatre lignes de commande suivantes :

f="200_nomIdentique.xxx"
echo "$f"
echo "${f%_*}"
echo "${f#*_}"

Donc :

for f in {220..200}_nomIdentique.xxx; do  # Pour tous les noms de fichiers 200 à 220_nomIdentique.xxx
    if test -f "$f"; then {                   # Si le fichier existe, alors 
        num=${f%_*}                               # Extraire le numéro qui précède le caractère `_`
        numPlusUn=$((num + 1))                    # Ajouter 1 à ce numéro
        nvNom="$numPlusUn_nomIdentique.xxx"       # Créer le nouveau nom de fichier
        mv "$f" "$nvNom"                          # Renommer le fichier avec le nouveau numéro
    }
done

Ce qui donne, en plus court :

for f in {220..200}_nomIdentique.xxx; do
    [ -f "$f" ] && mv "$f" "$((${f%_*} + 1))_nomIdentique.xxx"
done

Et si tu veux que la commande mv affiche le travail qu’elle fait
utilise son option verbose :

mv --verbose "$f" "$nvNom"

ou bien, en option courte : (mais dans un script, autant utiliser l’option longue)

mv -v "$f" "$nvNom"

pour chaque fichier renommé,
ça affichera un message comme ci-dessous :
renommé '220_nomIdentique.xxx' -> '221_nomIdentique.xxx'

1 J'aime

J’utilise rename fréquemment, j’avais d’abord cherché de ce côté mais n’ai pas trouvé comment incrémenter le nombre en fonction de la cible. Le problème est: comment passer une variable bash au script rename en Perl?

Merci et bravo,
en effet bash est plein de ressources.

La syntaxe de

$((${f%_*} + 1))_nomIdentique.xxx

demande une bonne maîtrise de la langue :wink:

En particulier, j’ignorais que bash acceptait le joker après l’opérateur «%».

1 J'aime

Remarque:
Il est essentiel de compter du plus haut vers le plus bas pour ne pas écraser chaque fichier par le premier.

Je trouve que la suppression d’une sous-chaîne dans une variable bash
est assez bien expliquée dans la page web suivante : wiki.bash-hackers.org → substring_removal

Il y a aussi tout plein de liens concernant bash
dans la page web suivante : wiki.bash-hackers.org → start

2 J'aime

je recommande à fond cette page

POST-SCRIPTUM
mon objectif était plus complexe qu’annoncé!
En effet la difficulté tenait à ce que les noms n’étaient pas totalement identiques!
Seule le numéro et le début de la chaîne le sont.

Dans ce cas, la solution de MicP me pose le même problème: comment récupérer la partie textuelle non identique (la partie supprimée par le code « %_*? »).

Désolé pour m’être trompé dans la question, mais votre réponse m’a tout de même déjà instruit et la question pourrait bien se poser en d’autres circonstances.

f="200_nomIdentique.xxx"
echo "$f"        # J'affiche le nom du fichier contenu dans la variable `f`
echo "${f%_*}"   # J'affiche ce qui est avant le caractère `_`
echo "${f#*_}"   # => c'est peut-être ce que tu demandes : tout ce qui est après le caractère `_`

Effectivement, j’avais essayé de faire en fonction de ce que je lisais dans ton script
parce que je n’avais pas autre chose.
Il aurait fallu décrire un peu plus le contexte en donnant une liste de noms de fichiers avant, et après l’exécution du script en fonction de ce que tu souhaiterais obtenir

Parce que s’il est question d’un nomIdentique qui ne l’est pas,
alors le script que je t’ai proposé ne convient forcement pas du tout.


Donc, donne nous un exemple de liste représentative de fichiers que tu aurais au départ
et la liste de ces mêmes fichiers telle que tu souhaiterais la voir après le l’exécution du script.

Merci.

salut
il faudrait préciser, mais tu peux toujours t’en sortir avec le sed :

actuellement, je l’écrirais ainsi :

mkdir -p temp; 
find . -maxdepth 1 -type f |while read fich; do fichier="$(basename $fich)" ; 
numero="$(echo $fichier |sed 's#^\([0-9]*\)[^0-9].*#\1#')";
reste="$(echo $fichier |sed 's#^[0-9]*\([^0-9].*\)#\1#')"; 
let numero2=$(echo $numero+1|bc);
cp ${numero}${reste} temp/$numero2${reste};
done

le let numero2=$(echo $numero+1|bc); ermet d’éviter la conversion octale ainsi un fichier qui commence par 015 devient un fichier qui commence par 16 , pas par 14 ( = 1*8+5 +1 ), mais le zéro saute

${f#_*}

limpide, évident . Comment n’y avoir pas pensé: ça me remet devant mon âge… Le cerveau aussi s’enkylose.

Ma solution initiale avec sed fonctionne, bien que je vous ai égaré en négligeant à tord le fait que les noms n’étaient pas identiques.
(Je vais le préciser dans l’énoncé initiale)