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.
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.
avec bash:
shopt -s globstar nullglob
rename _dbg.txt .txt **/*dbg*
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
Pour renommer de manière récursive, j'utilise les commandes suivantes:
find -iname \*.* | rename -v "s/ /-/g"
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\")' '{}' \;
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
-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
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