c'est une situation unique, qui peut être mieux expliquée avec un exemple
Exemple 1 Supposons que le dossier A
, B.mkv
et C.srt
soient deux fichiers dans le dossier. Je souhaite renommer ces fichiers en A.mkv
et A.srt
.
par exemple, un dossier appelé American Sniper (2014)
et American.Sniper.2014.1080p.BluRay.x264.YIFY.mkv
et American.Sniper.2014.Subtitle.BluRay.ShaAnig.srt
sont deux fichiers dans le dossier. Vous souhaitez renommer ces fichiers en American Sniper (2014).mkv
et American Sniper (2014).srt
.
Exemple 2
Cela devrait être récursif, disons que j'ai un dossier appelé A
, B
et C
sont deux sous-dossiers du dossier A
. le contenu de B et C est comme suit
Devrait être converti en
Même quand j'exécute l'algorithme/script/commande sur le dossier A
La 3ème chose à faire, c'est d'ignorer les fichiers cachés.
exemple
devrait aboutir à
enfin, il devrait fonctionner sur plusieurs dossiers à la fois
Il y a plusieurs façons d'aborder cette question. Veuillez lire attentivement les instructions pour de meilleurs résultats.
Dans cette réponse:
find
+ bash
approchePython est un langage assez puissant pour l’administration système et permet de parcourir l’arborescence de répertoires à l’aide de la fonction os.walk()
. Dans le script présenté ci-dessous, c'est exactement ce que nous faisons. Nous trouvons tous les fichiers et les exploitons sur chacun d'entre eux en déterminant le chemin complet de chaque fichier, son extension et en le renommant via la fonction os.rename()
.
#!/usr/bin/env python3
import os,sys
def get_all_files(treeroot):
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if f in __file__: continue
fullpath = os.path.realpath( os.path.join(dir,f) )
extension = fullpath.split('.')[-1]
newpath = os.path.join(dir, dir + '.' + extension)
print('Move ' + fullpath + ' to ' + newpath )
# os.rename(fullpath,newpath)
def main():
top_dir="."
# If directory not given, assume cwd
if len(sys.argv) == 2: top_dir=sys.argv[1]
get_all_files(top_dir)
if __== '__main__' : main()
NOTE: très très important est que pour renommer les fichiers, vous devez supprimer #
avant # os.rename(fullpath,newpath)
.
Toutes les règles standard pour les scripts s'appliquent: - enregistrez-le sous le nom add_location_name.py
dans le répertoire situé le plus haut - créez un exécutable avec chmod +x ./add_location_name.py
- exécutez-le avec ./add_location_name.py
Voici un exemple de la façon dont cela fonctionne dans la pratique. J'ai créé un répertoire avec deux autres, Movie A (2016)
et Movie B (2016)
. À l'intérieur, ils ont tous deux deux fichiers. Notre script habite dans le même répertoire:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
Ainsi, lorsque nous exécuterons le script, nous verrons le résultat suivant:
$ ./add_location_name.py
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv
La commande find
est utile à bien des égards, notamment lorsque vous effectuez des opérations sur plusieurs niveaux d'arborescence de répertoires. Dans ce cas particulier, nous pouvons l’utiliser pour filtrer tous les fichiers et les renommer.
Tout d’abord, laissez-moi vous donner la solution:
find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;
Ça a l'air long et effrayant, non? Mais ne vous inquiétez pas, voyons comment cela fonctionne.
Tout d’abord, vous devez reconnaître qu’il y a deux choses qui se passent: la commande find
localise tous les fichiers et la partie bash
permet de renommer la partie. À l'extérieur, nous voyons la commande simple:
find -type f -exec <COMMAND> \;
Cela ne trouve que tous les fichiers (pas de répertoires ni de liens symboliques) et appelle une autre commande chaque fois qu’il trouve un fichier. Dans ce cas, le COMMAND spécifique que nous avons est bash
.
Alors, que fait la partie bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}"
? Bien, reconnaissons tout d’abord la structure: bash -c 'command1;command2' arg0 arg1
. Chaque fois que le drapeau -c
est utilisé, le premier argument de ligne de commande arg0
sera défini comme $0
, nom de shell, de sorte qu'il n'a pas d'importance, mais "{}"
est important. Il s’agit de l’espace réservé cité pour le nom de fichier que find
passera en tant qu’argument à bash
.
À l'intérieur de la commande bash, nous extrayons le chemin du fichier fp=$(dirname "$1")
, le nom du répertoire fn=$(basename "$fp")
et l'extension du fichier ou le préfixe px="${1##*.}"
. Tout cela fonctionne très bien puisque nous exécutons la commande à partir du répertoire le plus haut (très important!). Enfin, le mv "$1" "$fp"/"$fn"."$px"' sh "{}"
renomme le fichier d'origine que find
nous a attribué au nouveau nom de fichier que nous construisons avec "$fp"/"$fn"."$px"
en utilisant toutes ces variables.
Le test de la commande est effectué sur le même répertoire que précédemment:
$ tree
.
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 4 files
Et si nous exécutons la commande, avec echo
au lieu de mv
, nous pouvons voir que chaque nom de fichier est renommé, respectivement.
$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv
Rappelez-vous: la commande ci-dessus utilise echo
uniquement à des fins de test. Lorsque vous utilisez mv
, il n'y a pas de sortie, la commande est donc silencieuse.
Les deux approches ci-dessus utilisent une traversée d'arbre récursive. Comme dans votre exemple, vous n’avez que deux niveaux dans l’arborescence (répertoire movie et fichiers), nous pouvons simplifier notre commande Shell précédente comme suit:
for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Encore une fois, même idée - remplacez echo
par mv
lorsque vous êtes sûr qu’il fonctionne correctement.
Les résultats du test sont les mêmes:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
Donné
$ tree
.
└── A
├── B
│ ├── somefile
│ ├── T.txt
│ ├── X.srt
│ └── Z.mkv
└── C
├── somefile
├── T.txt
├── W.mkv
└── Y.srt
3 directories, 8 files
ensuite
$ find A -type f \( -name '*.mkv' -o -name '*.srt' \) -not -name '.*' -exec sh -c '
for f; do
dir="${f%/*}" ; ext="${f##*.}" ; new="${dir##*/}"
echo mv -- "$f" "${dir}/${new}.${ext}"
done' sh {} +
mv -- A/C/Y.srt A/C/C.srt
mv -- A/C/W.mkv A/C/C.mkv
mv -- A/B/Z.mkv A/B/B.mkv
mv -- A/B/X.srt A/B/B.srt
(retirez la echo
une fois que vous êtes bien sûr il va faire ce que vous voulez).