web-dev-qa-db-fra.com

Supprimer les espaces blancs de début des fichiers, dossiers et leurs sous-dossiers

Je suis venu avec cela, mais malheureusement, cela n’affecte pas les fichiers/dossiers des sous-dossiers.

find . -exec rename "s/^\s+//" {} \;

Structure du dossier:

foo
|-- \ bar
`-- \ foo1
    |-- \ bar1
    `-- \ foo2
        `-- \ bar2
4
Sascha

Renommer doit être fait de bas en haut

Le problème est que vous devez renommer les répertoires de bas en haut. Sinon, la commande essaiera de renommer les fichiers et les répertoires qui se trouvent dans des dossiers déjà déplacés (renommés) et ne les trouvera donc plus.

C’est ici que vous pouvez utiliser os.walk() de python, en combinaison avec topdown=False

Dans un petit 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:
        if f.startswith(" "):
            shutil.move(root+"/"+f, root+"/"+f.strip())
    for dr in dirs:
        if dr.startswith(" "):
            shutil.move(root+"/"+dr, root+"/"+dr.strip())

Utiliser

  • Copiez le script dans un fichier vide, enregistrez-le sous le nom no_space.py
  • Exécutez-le à l'aide de la commande:

    python3 /path/to/no_space.py /path/to/directory/to/rename
    
3
Jacob Vlijm

Comme indiqué dans d'autres réponses, le problème principal est que ^ ancre le début du chemin plutôt que le début du nom de fichier. Il existe plusieurs façons de contourner ce problème avec find et rename: le plus sûr serait probablement d'utiliser -execdir à la place de -exec de sorte que tous les composants de chemin soient réduits à ./, puis remplacez le motif \./\s+

De même, si vous renommez des répertoires en incluant éventuellement les ancêtres d'autres fichiers/répertoires à renommer, vous devez effectuer une traversée en profondeur d'abord.

Mettre ensemble,

find . -depth -name ' *' -execdir rename -vn -- 's#\./\s+##' {} +

ou (fonctionnellement équivalent, mais un peu plus facile à voir ce qui se passe) en utilisant une "longueur nulle" pour le séparateur de chemin

$ find . -depth -name ' *' -execdir rename -vn -- 's#(?<=\./)\s+##' {} +
./ bar2 renamed as ./bar2
./ foo2 renamed as ./foo2
./ bar1 renamed as ./bar1
./ foo1 renamed as ./foo1
./ bar renamed as ./bar

[NOTE: retirez le -n une fois que vous êtes sûr qu'il fait ce que vous voulez]

2
steeldriver

Je pense que le problème est avec le format de sortie de find, qui inclut le chemin complet. Donc pour bar2 vous aurez

./ foo1/ foo2 /bar2

ce renommage ne comprendra pas correctement.

Une solution consiste à utiliser un script pour faire chaque dossier de manière récursive comme ceci:

#!/bin/bash
# if argument given consider it is the directory to parse
if [ -n "$1" ]; then
    cd "$1"
fi
# rename all files in current folder
find . -maxdepth 1 -printf '%f\0'  | xargs -0r -n 1 rename -nono 's/^\s+//'
# No, repeat for all subfolders with current script (we are in the subfolder)
find . -maxdepth 1 -type d -not -name '.' -print0 | xargs -0r -n 1 "$(readlink -f $0)"
1
Camilio