web-dev-qa-db-fra.com

Commande pour créer des répertoires ciblés numérotés de manière séquentielle et des fichiers de déplacement par lots

Je crée une vidéo timelapse en scindant une vidéo en images individuelles, en utilisant G'MIC via la ligne de commande pour établir une moyenne toutes les 7 images, puis les résultats sont générés sur de nouvelles images, ce qui donnera les images pour le timelapse. vidéo sans bruit qui a fière allure). Comme vous pouvez l’imaginer, j’ai beaucoup de cadres - plusieurs milliers d’images individuelles dans un répertoire nommé séquentiellement (image1.tiff, image2.tiff, etc.). J'ai trouvé un script qui fonctionne parfaitement pour déplacer les fichiers - une fois ...

k=1; find source/ -type f | while read file; do
     [[ k++ -le 7 ]] && mv "$file" target/ 
done 

Ce dont j'ai besoin maintenant, c'est de faire ce script

  1. se répéter jusqu'à ce que tous les fichiers soient déplacés et
  2. créez des répertoires cibles numérotés séquentiellement (1, 2, 3, etc.) au fur et à mesure, ainsi je me retrouve avec plusieurs centaines de répertoires contenant chacun 7 images.

Juste pour clarifier, le répertoire 1 devrait contenir les images 1-7, le répertoire 2 devrait contenir les images 8-14, etc.

Toute aide est grandement appréciée, je suis plutôt coincé avec celui-ci.

4
Tim

Le script (python) ci-dessous crée des sous-dossiers et organise vos fichiers dans ces dossiers:

Aditionellement:

  • Le script calcule le nombre de dossiers et ajoute des zéros à gauche aux noms des dossiers pour un tri correct (puisque vous avez mentionné des milliers de fichiers, ce qui signifie des centaines de dossiers).
  • Le nombre de fichiers par dossier peut varier en fonction de votre paramétrage dans l'en-tête du script.

Le script suppose:

  • Tous les fichiers ont une extension, tous les fichiers ont une extension identique
  • Vos fichiers sont nommés image1.tiff, image2.tiff etc (pas de zéros).

Le scénario

#!/usr/bin/env python3
import os
import math
import shutil
#---
directory = "/path/to/files"      # path to your files
n_perfolder = 7                   # number of files per sub folder
#--
# creating file list, extension
f_list = os.listdir(directory); ext = f_list[0].split(".")[-1]
# calculate number of folders
n_folders = math.ceil(len(f_list)/n_perfolder)
# creating folder names, including leading zeros
folders = [str(fn+1) for fn in range(n_folders)]
fl_names = [(len(max(folders, key=len))-len(fl))*"0"+fl for fl in folders]
# creating folders and allocate files 
for i in range(len(fl_names)):
    mkfolder = directory+"/"+fl_names[i]
    if not os.path.exists(mkfolder):
        os.makedirs(mkfolder)
        r = range(i*n_perfolder+1, i*n_perfolder+n_perfolder+1)
        for n in r:
            try:
                file = directory+"/"+"image"+str(n)+"."+ext
                target = mkfolder+"/"+"image"+str(n)+"."+ext
                shutil.copyfile(file, target)
            except FileNotFoundError:
                pass

Comment utiliser

Copiez le script dans un fichier vide, dans la section head, définissez le répertoire dans vos fichiers et le nombre de fichiers par sous-répertoire, enregistrez-le sous le nom organize.py.

Exécutez-le à l'aide de la commande:

python3 /path/to/organize.py

Remarque

Si vous souhaitez déplacer les fichiers au lieu de les copier, remplacez la ligne:

shutil.copyfile(file, target)

par:

shutil.move(file, target)

(attention au retrait!)

3
Jacob Vlijm

Si cela ne vous dérange pas que tout soit déplacé séparément:

#! /bin/bash
for ((i = 1; ; i++))
do
    mkdir -p target-$i
    for j in $(seq $((i*7 - 6)) $((i*7)))
    do
        mv -t "target-$i" "source/image$j.tiff" || exit 1
    done
done

Ou plus concis:

find source -type f -name 'image*.tiff' -print0 | \
  sort -z --version-sort | \
  xargs -0n7 bash -c 'TARGET=target-$((${1//[^0-9]/} / 7 + 1)); \
    echo mkdir -p "$TARGET"; \
    echo mv -t "$TARGET" "$@"' move-7

Explication:

  1. -print0 imprime les noms de fichiers séparés par le caractère NUL (\0). C'est le moyen le plus sûr de transmettre les noms de fichiers en sortie à d'autres commandes.
  2. sort avec -z cherche une entrée non délimitée, et le tri de la version nous permet de trier en toute sécurité les nombres de longueur variable, de sorte que image2.tiff vienne avant image119.tiff
  3. xargs peut limiter le nombre d'arguments appliqués à chaque commande avec -n, nous utilisons donc -n7. Le -0 est pour une entrée non délimitée.
  4. Nous extrayons le quotient du nombre du premier argument $((${1//[^0-9]/} / 7 + 1)) - ${1//[^0-9]/} supprime tout l'élément de l'argument qui n'est pas un nombre. La division entière assure que nous obtenons le quotient.
  5. Cela devrait être plus rapide, car nous exécutons exactement le nombre de mvs requis.

Inspectez les commandes générées et, si elles vous conviennent, exécutez-les à nouveau après avoir supprimé les echos.

KasiyA a un modification intéressante à cela.


Réponse de JJoao rappelle rename . Tout d’abord, créez tous les répertoires:

FILES=(source/image*.tiff)
COUNT=${#FILES[@]}
DIR_NUM=$((COUNT / 7 + 1))
seq 1 $DIR_NUM | xargs bash -c 'mkdir -p "${@/#/target-}"'

rename -n 's;source/image(\d+)\.tiff$;"target-".int($1 / 7 - 1)."/image".$1.".tiff";e' source/image*.tiff

En fait, nous pourrions appliquer les quatre premières lignes à toutes les solutions ici et ignorer les répétitions mkdir -p.

2
muru
sevenfile=0
newdir=1
for file in `ls -v /path/to/source/image*.tiff` ; do
    mkdir -p "$newdir" && mv "$file" "$newdir" 
    [[ ++sevenfile -eq 7 ]] && sevenfile=0 &&  ((newdir++))
done
  • La commande ls -v trie les fichiers comme une sorte naturelle de numéro (de version).
    Vous pouvez analyser la commande ls dans ce cas, car tous les fichiers sont spécifiques et ne sont que image*.tiff.
  • mkdir -p $newdir crée le répertoire en fonction de la variable newdir.

  • mv "$file" "$newdir" déplace le fichier dans le répertoire spécifié par newdir.

  • Réinitialisez le sevenfile=0 à zéro lorsque 7 fichiers ont été déplacés ([[ ++sevenfile -eq 7 ]]) et augmentez la valeur newdir.

Notez que changez /path/to/source/ en votre répertoire source actuel.

Si vous ne souhaitez pas analyser la commande ls et si les noms de fichier incluent des espaces, des nouvelles lignes, etc.:

find /path/to/source/ -type f -name 'image*.tiff' -print0 | \
     sort -z --version-sort | while IFS= read -d '' -r file; do \
     mkdir -p "$newdir" && mv "$file" "$newdir" ;
     [[ ++sevenfile -eq 7 ]] && sevenfile=0 &&  ((newdir++));
done
2
αғsнιη
#!/usr/bin/Perl

open(F,"-|","ls source/*") or die;

while(<F>){ chomp;
  if(/(\d+).tiff/){
     $dir= "target-" . (1+int($1/7));
     mkdir($dir) unless -d $dir;
     system "mv $_ $dir";
  }
}
1
user216043