J'ai un grand nombre de dossiers avec un fichier nommé genome.txt
dont j'ai besoin pour cp
dans le même dossier. J'essaie de comprendre comment faire pour que les fichiers ressemblent à genome1.txt
, genome2.txt
, etc. Je recherche une solution simple à cela.
Cela peut être fait avec un simple script Shell qui utilise la structure find ...|while read var ; do ... done
(très courante dans le traitement des noms de fichiers). Le script bash ci-dessous fonctionne sur le répertoire actuel (en haut) et prend un seul argument pour la destination.
#!/bin/bash
find -name "genome.txt" -print0 | while IFS= read -r -d '' path
do
base=$(basename --suffix=".txt" "$path")
new_path="${1%/}"/"$base"$counter".txt"
echo "$path" "$new_path"
counter=$(( $counter +1 ))
done
>>> NOTE <<< : le script utilise echo
uniquement à des fins de test. Lorsque vous êtes satisfait des chemins résultants, remplacez echo
par mv
pour déplacer tous les noms de fichiers ou cp
pour copier tous les noms de fichiers.
Exemple:
bash-4.3$ tree
.
├── destination
├── dir1
│ └── genome.txt
├── dir2
│ └── genome.txt
├── dir3
│ └── genome.txt
└── move_enumerated.sh
4 directories, 4 files
bash-4.3$ ./move_enumerated.sh ./destination
./dir2/genome.txt ./destination/genome.txt
./dir3/genome.txt ./destination/genome1.txt
./dir1/genome.txt ./destination/genome2.txt
Ce script peut être encore amélioré pour le rendre plus général, où l'utilisateur peut spécifier le nom de fichier, le répertoire supérieur à parcourir et la destination en tant qu'arguments de ligne de commande:
#!/bin/bash
find "$2" -name "$1" -print0 | while IFS= read -r -d '' path
do
base=$(basename --suffix=".txt" "$path")
new_path="${3%/}"/"$base"$counter".txt"
echo "$path" "$new_path"
counter=$(( $counter +1 ))
done
Essai:
bash-4.3$ ./move_enumerated.sh "genome.txt" "./testdir" "./testdir/destination"
./testdir/dir2/genome.txt ./testdir/destination/genome.txt
./testdir/dir3/genome.txt ./testdir/destination/genome1.txt
./testdir/dir1/genome.txt ./testdir/destination/genome2.txt
Dans l'ensemble, le script utilise la structure command | while read variable ; do ... done
. C'est une approche très courante, et elle est fréquemment utilisée pour éviter de traiter avec ls
et des noms de fichiers difficiles pouvant rompre les scripts.
Sur le côté gauche du tuyau, nous avons la commande find
, qui prend le répertoire comme argument (et si ce n'est pas indiqué, GNU find
utilisé dans Linux suppose que .
- le répertoire de travail en cours). Les autres options incluent -name
qui est le nom de fichier spécifique que nous recherchons et -print0
qui est utilisé pour afficher les résultats délimités via le caractère non imprimable \0
. Il est fréquemment utilisé pour éviter de séparer les caractères de nouvelle ligne ou autres, car ces caractères peuvent potentiellement apparaître dans le nom du fichier même et par conséquent briser le script.
Sur le côté droit du tuyau, nous avons la structure while IFS= read -r -d '' ; do . . . done
. La boucle while
avec read
Shell intégré est fréquemment utilisée pour la vraie entrée stdin
, qui dans ce cas provient du tuyau. IFS=
-r
et -d ''
sont nécessaires pour nous assurer de recevoir les noms de fichiers en toute sécurité et de reconnaître que chaque élément est délimité par \0
.
Le reste du script est assez facile. Nous extrayons le nom de base du fichier en utilisant la commande basename
. Étant donné que dans ce cas, nous traitons spécifiquement avec des extensions connues et attendons un seul point dans le nom du fichier, nous pouvons utiliser --suffix=".txt"
pour supprimer cette partie, en laissant genome
. Nous construisons ensuite un nouveau chemin d'accès au fichier via la destination de jonction, le nom de base et la variable compteur. Notez que nous utilisons le développement des paramètres avec l'argument "${3%/}"
(dossier de destination) dans notre script amélioré. Ceci est fait pour s'assurer que, que l'utilisateur ajoute ou non le caractère /
à la ligne de commande (./destination
ou ./destination/
), nous extrayons uniquement le nom de répertoire nu et nous le relions via /
avec le nom de base. Notez également que la variable counter
n’a pas été définie initialement. Le premier nom de fichier que nous recevons sera donc tout simplement genome.txt
Après cela, la variable compteur sera incrémentée et ainsi créée et apparaîtra lorsque nous traiterons avec d’autres noms de fichiers.
Pour plus d'informations, veuillez lire Noms de fichier et noms de chemin dans Shell: comment le faire correctement .