web-dev-qa-db-fra.com

Remplacer un mot dans un nom de répertoire et dans les noms de fichiers de ce répertoire

J'ai une structure de répertoire comme celle-ci:

Bookname Edition 1
  Bookname Edition 1 type1.pdf
  Bookname Edition 1 type2.pdf
Bookname Edition 2
  Bookname Edition 2 type1.pdf
  Bookname Edition 2 type2.pdf

Je veux changer de manière récursive le nom de Edition en Volume du répertoire et les noms de fichiers dans ces répertoires.

J'ai commencé avec ça et c'est bien si je suis dans le répertoire:

for f in *.pdf; do
    a="$(echo $f | sed s/Edition/Volume/)"
    mv "$f" "$a"
done

Ensuite, j'ai essayé de changer tous les fichiers sous les répertoires, et c'est à ce moment-là que je me suis retrouvé coincé ...

S'il vous plaît pouvez-vous me dire comment faire cela ou me donner un meilleur moyen de le faire. Il y a 15000 PDF dans 100 annuaires.

7
Bishop

Si votre structure n'a que deux niveaux, vous n'avez pas besoin d'utiliser la récursivité.

Ne pas analyser les noms de fichiers avec sed. Si vous souhaitez utiliser la syntaxe de style regex et sed pour renommer les fichiers, utilisez rename. Si vous utilisez Ubuntu 17.10, vous devez l’installer.

Sudo apt install rename

Ensuite, vous pouvez utiliser réponse de pa408 .

Avec rename, utilisez l’option -n pour le test.

rename -n 'expression' file(s)

Vous pouvez également simplement utiliser la commande mv. En tant que commande d'une ligne:

for d in ./*/; do mv -v "$d" "${d/Edition/Volume}"; done; for f in ./*/*; do mv -v "$f" "${f/Edition/Volume}"; done

Vous pouvez utiliser echo pour tester mv, c'est-à-dire echo mv -v source dest, mais cela donne des résultats inexacts ici, sauf si vous testez puis exécutez les boucles séparément.

En tant que script:

#!/bin/bash

# rename directories first
for d in ./*/; do
    mv -v "$d" "${d/Edition/Volume}"
done

# now rename files
for f in ./*/*; do
    mv -v "$f" "${f/Edition/Volume}"
done

mv et rename reconnaissent -- pour indiquer la fin des options. Puisque tous les chemins commencent par ./ dans cet exemple, nous n’avons pas besoin de l’utiliser, mais si les chemins peuvent commencer par -, utilisez -- à la fin des options, par exemple rename -n -- 's/foo/bar/' *, pour empêcher ces chemins d’être interprétés comme des options.

11
Zanna

Vous pouvez utiliser la commande renameà deux reprises pour accomplir cette tâche:

rename 's/Edition/Volume/' */        # rename the directories
rename 's/Edition/Volume/' */*.pdf   # rename the PDF files inside

Voici deux questions similaires:

6
pa4080

Sur les répertoires à plusieurs niveaux, vous pouvez le faire en une seule étape, mais le problème est que vous devez vous assurer de renommer les répertoires de bas en haut pour empêcher la commande ou le script de modifier le nom du répertoire avant que son contenu ne soit modifié.

En python, vous pouvez utiliser:

os.walk

en combinaison avec

topdown=False

Dans un script:

#!/usr/bin/env python3
import os
import shutil
import sys

for root, dirs, files in os.walk(sys.argv[1], topdown=False):
    for f in files:
        shutil.move(
            root+"/"+f, root+"/"+f.replace("Edition", "Volume").strip()
        )
    for dr in dirs:
        shutil.move(
            root+"/"+dr, root+"/"+dr.replace("Edition", "Volume").strip()
        )

Enregistrez le script sous change_name.py, exécutez-le avec le répertoire comme argument:

python3 /path/to/change_name.py <directory>

Cela fonctionne de manière récursive sur n'importe quel nombre de niveaux.

5
Jacob Vlijm

Utilisez find avec l'option -depth associée à prename:

find [DIRS...] -depth | prename -n 's|Edition(?=[^/]*$)|Volume|'

Explication:

  • -depth sélectionne les enfants du répertoire avant leurs parents. Un outil "consommant" les noms de chemin sélectionnés pour renommer peut alors renommer les enfants avant leurs parents.

  • s|Edition(?=[^/]*$)|Volume| remplace la première occurrence de Edition dans le nom du chemin par Volume mais uniquement si le reste ne contient pas un /, i. e. il ne s'applique qu'au dernier composant du nom du chemin d'accès (obtenu par le code (?=[^/]*$) positif).

  • -n indique à prename de ne pas renommer les chemins, mais d'indiquer comment il les renommerait. Supprimez cette option pour les renommer.

1
David Foerster