4 votes

Commande permettant de créer des répertoires ciblés numérotés séquentiellement et de déplacer des fichiers par lot

Je suis en train de créer une vidéo timelapse en divisant une vidéo en images individuelles, en utilisant G'MIC via la ligne de commande pour faire la moyenne toutes les 7 images, puis en sortant les résultats vers de nouvelles images qui donneront les images pour le timelapse (de cette façon, j'obtiens une vidéo sans bruit qui a l'air bien). Comme vous pouvez l'imaginer, j'ai beaucoup d'images - plusieurs milliers d'images individuelles dans un répertoire, nommées 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ète jusqu'à ce que tous les fichiers soient déplacés et
  2. créer des répertoires cibles numérotés séquentiellement (1, 2, 3, etc.) au fur et à mesure, de sorte que je me retrouve avec plusieurs centaines de répertoires contenant chacun 7 images.

Pour clarifier, le répertoire 1 doit contenir les images 1 à 7, le répertoire 2 doit contenir les images 8 à 14, etc.

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

3voto

Jacob Vlijm Points 78990

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

En outre :

  • Le script calcule le nombre de dossiers et ajoute des zéros de tête aux noms de 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 réglage dans l'en-tête du script.

Le script suppose :

  • Tous les fichiers ont une extension, tous les fichiers ont le même extension
  • Vos fichiers sont nommés image1.tiff , image2.tiff etc. (sans zéros en tête).

Le script

#!/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

Mode d'emploi

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

Exécutez-le par la commande :

python3 /path/to/organize.py

Note

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 à l'indentation !)

2voto

muru Points 180007

Si ça 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 NUL ( \0 ) personnage. C'est le moyen le plus sûr de transmettre des noms de fichiers en sortie à d'autres commandes.
  2. sort con -z recherche les entrées non délimitées, et le tri par version nous permet de trier en toute sécurité les nombres de longueur variable, de sorte que image2.tiff vient avant image119.tiff
  3. xargs peut limiter le nombre d'arguments appliqués à chaque commande avec -n donc ici nous utilisons -n7 . Le site -0 est pour les entrées non délimitées.
  4. Nous extrayons le quotient du nombre du premier argument $((${1//[^0-9]/} / 7 + 1)) - ${1//[^0-9]/} supprime tout ce qui, dans l'argument, n'est pas un nombre. La division entière permet d'obtenir le quotient.
  5. Ceci devrait être plus rapide, puisque nous exécutons exactement le nombre de mv nécessaires.

Inspectez les commandes produites, et si elles semblent correctes, exécutez à nouveau le programme après avoir supprimé l'option echo s.


La réponse de JJoao apporte rename à l'esprit. D'abord, faites 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 sauter l'étape répétée de mkdir -p .

2voto

αғsнιη Points 33236
sevenfile=0
newdir=1
for file in "$(ls -bv /path/to/source/image*.tiff)"; do
    mkdir -p "$newdir" && mv "$file" "$newdir" 
    [[ ++sevenfile -eq 7 ]] && sevenfile=0 &&  ((newdir++))
done
  • ls -v trie les fichiers comme un tri naturel de numéros (de version).
    Vous pouvez analyser les ls dans votre cas, parce que tous les fichiers sont spécifiques et seulement sont image*.tiff .

  • mkdir -p $newdir crée le répertoire en se basant sur newdir variable.

  • mv "$file" "$newdir" déplace le fichier dans le répertoire qui newdir précise.

  • Réinitialiser le sevenfile=0 à zéro lorsque 7 fichiers ont été déplacés ( [[ ++sevenfile -eq 7 ]] ) et l'incrémenter à newdir valeur.

Notez que le changement /path/to/source/ dans votre répertoire source actuel.

Si vous ne voulez pas que l'analyse syntaxique du ls et si le nom des fichiers comprend 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

1voto

#!/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";
  }
}

0voto

bac0n Points 4841

Vous pouvez utiliser xargs (-n ou --max-args) pour définir le nombre de fichiers à déplacer, mais gardez à l'esprit que les arguments sont limités à ARG_MAX.

#!/bin/bash

images="./source/image*.tiff"
target="./target"

ls -v $images | xargs -n 7 | while read -a files; do mkdir $target/$((++n)) && mv -t $target/$n ${files[@]}; done

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X