web-dev-qa-db-fra.com

Rechercher plusieurs fichiers de manière récursive et renommer sous Linux

J'ai des fichiers comme a_dbg.txt, b_dbg.txt ... dans un système Suse 10. Je veux écrire un script shell bash qui devrait renommer ces fichiers en supprimant "_dbg".

Google m'a suggéré d'utiliser la commande rename. J'ai donc exécuté la commande rename _dbg.txt .txt *dbg* sur le CURRENT_FOLDER

Mon CURRENT_FOLDER actuel contient les fichiers ci-dessous.

CURRENT_FOLDER/a_dbg.txt
CURRENT_FOLDER/b_dbg.txt
CURRENT_FOLDER/XX/c_dbg.txt
CURRENT_FOLDER/YY/d_dbg.txt

Après avoir exécuté la commande rename

CURRENT_FOLDER/a.txt
CURRENT_FOLDER/b.txt
CURRENT_FOLDER/XX/c_dbg.txt
CURRENT_FOLDER/YY/d_dbg.txt

Son pas faire récursivement, comment faire cette commande pour renommer les fichiers dans tous les sous-répertoires. Comme XX et YY, je vais avoir tant de sous-répertoires dont le nom est imprévisible. Et aussi mon CURRENT_FOLDER aura d'autres fichiers aussi.

55
rashok

Vous pouvez utiliser find pour rechercher tous les fichiers correspondants de manière récursive:

$ find . -iname "*dbg*" -exec rename _dbg.txt .txt '{}' \;

EDIT: que sont le '{}' et le \;?

L'argument -exec permet à find execute rename de tout fichier correspondant trouvé. '{}' sera remplacé par le chemin du fichier. Le dernier jeton, \;, n’est là que pour marquer la fin de l’expression exec.

Tout ce qui est décrit joliment dans la page de manuel de find:

 -exec utility [argument ...] ;
         True if the program named utility returns a zero value as its
         exit status.  Optional arguments may be passed to the utility.
         The expression must be terminated by a semicolon (``;'').  If you
         invoke find from a Shell you may need to quote the semicolon if
         the Shell would otherwise treat it as a control operator.  If the
         string ``{}'' appears anywhere in the utility name or the argu-
         ments it is replaced by the pathname of the current file.
         Utility will be executed from the directory from which find was
         executed.  Utility and arguments are not subject to the further
         expansion of Shell patterns and constructs.
109
kamituel

avec bash:

shopt -s globstar nullglob
rename _dbg.txt .txt **/*dbg*
11
glenn jackman

petit script que j'ai écrit pour remplacer tous les fichiers avec l'extension .txt en extension .cpp sous/tmp et sous-répertoires de manière récursive

#!/bin/bash

for file in $(find /tmp -name '*.txt')
do
  mv $file $(echo "$file" | sed -r 's|.txt|.cpp|g')
done
11
VishnuVardhanA

Pour renommer de manière récursive, j'utilise les commandes suivantes:

find -iname \*.* | rename -v "s/ /-/g"
11
Gantan

Le script ci-dessus peut être écrit sur une ligne:

find /tmp -name "*.txt" -exec bash -c 'mv $0 $(echo "$0" | sed -r \"s|.txt|.cpp|g\")' '{}' \;
2
Manh Tai

Renommez les fichiers et les répertoires avec find -execdir | rename

Si vous voulez renommer les fichiers et les répertoires, pas simplement avec un suffixe, c'est un bon modèle:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find . -depth -execdir rename 's/findme/replaceme/' '{}' \;

L'option awesome -execdir crée une cd dans le répertoire avant d'exécuter la commande rename, contrairement à -exec.

-depth veille à ce que le changement de nom soit effectué en premier lieu sur les enfants, puis sur les parents, afin d'éviter d'éventuels problèmes avec des répertoires parent manquants.

-execdir est requis car le changement de nom ne fonctionne pas correctement avec les chemins d'entrée autres que les noms de base, par exemple. les échecs suivants:

rename 's/findme/replaceme/g' acc/acc

Le piratage PATH est requis car -execdir présente un inconvénient très gênant: find est extrêmement avisé et refuse de faire quoi que ce soit avec -execdir si vous avez des chemins relatifs dans votre variable d'environnement PATH, par exemple. ./node_modules/.bin, échouant avec:

find: le chemin relatif ‘./node_modules/.bin’ est inclus dans la variable d’environnement PATH, qui n’est pas sécurisée en combinaison avec l’action -execdir de find. Veuillez supprimer cette entrée de $ PATH

Voir aussi: https://askubuntu.com/questions/621132/why-using-the-execdir-action-is-insecure-for-directory-which-is-in-the-path/1109378#1109378

-execdir est une GNU find extension to POSIX . rename est basé sur Perl et provient du paquetage rename. Testé sous Ubuntu 18.10.

Renommer la solution de contournement de lookahead

Si vos chemins d'entrée ne proviennent pas de find, ou si vous en avez assez des inconvénients de chemins relatifs, nous pouvons utiliser un préfixe Perl pour renommer en toute sécurité les répertoires comme suit:

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'

Je n'ai pas trouvé d'analogue pratique pour -execdir avec xargs: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686

Le sort -r est nécessaire pour garantir que les fichiers viennent après leurs répertoires respectifs, car les chemins les plus longs suivent les plus courts avec le même préfixe. 

Vous pouvez utiliser ceci ci-dessous.

rename --no-act 's/\.html$/\.php/' *.html */*.html
0
井上智文

Si vous voulez juste renommer et que vous utilisez un outil externe, vous pouvez utiliser rnm . La commande serait:

#on current folder
rnm -dp -1 -fo -ssf '_dbg' -rs '/_dbg//' *

-dp -1 le rend récursif dans tous les sous-répertoires.

-fo implique le mode fichier uniquement.

-ssf '_dbg' recherche les fichiers avec _dbg dans le nom du fichier.

-rs '/_dbg//' remplace _dbg par une chaîne vide.

Vous pouvez aussi exécuter la commande ci-dessus avec le chemin du CURRENT_FOLDER:

rnm -dp -1 -fo -ssf '_dbg' -rs '/_dbg//' /path/to/the/directory
0
Jahid