Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 20/02/2020, à 17:42

Fantakov

[Résolu] Boucle for traitée par taille

Bonjour à tous,

J'ai un dossier contenant plusieurs dizaines de milliers d'images de tout types et tailles que j'aimerais diviser en plusieurs dossiers de 1000 images.

J'ai trouvé un bout de code sur le forum que j'ai un peu modifié et qui fonctionne très bien pour répartir les fichiers dans des dossiers de 1000 :

nbImg=1000
cpt=0
j=0

mkdir img$j

for i in * ; do
	cpt=`expr $cpt + 1`	
	mv "$i" $PWD/img$j
	modulo=`expr $cpt % $nbImg`
	if [ $modulo -eq 0 ]; then
		j=`expr $cpt / $nbImg`
		mkdir img$j
	fi
done

Le problème c'est que j'aimerais qu'ils soient triés par taille avant d’être dispatchés.
En gros avoir les images de plusieurs Mo dans le dossier img1 et celles de 2ko dans le dossier img50.

Comment demander à for de faire son boulot par ordre de taille ?
Merci

Dernière modification par Fantakov (Le 20/02/2020, à 19:47)

Hors ligne

#2 Le 20/02/2020, à 18:28

pingouinux

Re : [Résolu] Boucle for traitée par taille

Bonjour,
Tu peux essayer ceci (c'est du bash)

nbImg=1000
rep=0
n=0
mkdir "img$rep"

while read fic; do
    if ((n==nbImg)); then
        n=0     
        ((rep++))
        mkdir "img$rep"
    fi  
    mv "$fic" "$PWD/img$rep"
    ((n++)) 
done < <(ls -S *)

Hors ligne

#3 Le 20/02/2020, à 19:38

Watael

Re : [Résolu] Boucle for traitée par taille

je ne le dirai jamais assez : gare aux fichiers avec des espaces dans leur nom !

 $ while read -d '' size filename; do echo ">$filename<"; done < <(find ./ -maxdepth 1 -type f -printf '%s %p\0' | sort -z -k1,1n )

Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#4 Le 20/02/2020, à 19:41

Fantakov

Re : [Résolu] Boucle for traitée par taille

Salut, ça marche comme il faut c'est impeccable les fichiers se rangent correctement dans leurs dossiers par taille.
Seul petit détail, à la fin du script pour chaque fichier ça m'affiche une ligne du type

mv: impossible d'évaluer 'monfichier': Aucun fichier ou dossier de ce type

Je risque de réutiliser de temps en temps se script si jamais tu sais comment cacher l'erreur (pour le coté esthétique).

En tout cas les fichiers sont correctement déplacés c'est le principal.

Merci beaucoup Pingouinux !

edit pour Watael : J'ai vérifié pour le script de Pingouinux et celui que j'ai mis en post 1 les deux traitent bien les fichiers avec des espaces, les variables sont entre guillemets.

Dernière modification par Fantakov (Le 20/02/2020, à 19:46)

Hors ligne

#5 Le 20/02/2020, à 20:14

Watael

Re : [Résolu] Boucle for traitée par taille

je compte les retours chariot dans les espaces.
j'ai oublié de mettre des points de suspension : espaces,...


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#6 Le 20/02/2020, à 20:30

kamaris

Re : [Résolu] Boucle for traitée par taille

Ouais, ben moi je dis que c'est pas assez tout ça, parce que si j'ai des antislashs dans mes noms de fichier, ou des espaces à la fin, ça marchera pas tongue
Donc :

while IFS='' read -rd '' line; do echo ">${line#* }<"; done < <(find ./ -maxdepth 1 -type f -printf '%s %p\0' | sort -z -k1,1n )

Hors ligne

#7 Le 20/02/2020, à 20:44

pingouinux

Re : [Résolu] Boucle for traitée par taille

Fantakov #4 a écrit :

Je risque de réutiliser de temps en temps se script si jamais tu sais comment cacher l'erreur (pour le coté esthétique).

Ceci devrait être mieux, mais c'est du bricolage

nbImg=1000
rep=0
n=0
mkdir "img$rep"

while read fic; do
    [ -d "$fic" ] && continue
    if ((n==nbImg)); then
        n=0
        ((rep++))
        mkdir "img$rep"
    fi
    mv "$fic" "$PWD/img$rep"
    ((n++))
done < <(ls -Sd *)

Hors ligne

#8 Le 20/02/2020, à 21:05

Watael

Re : [Résolu] Boucle for traitée par taille

ça ne règle pas le "problème" des retours chariot.
et find ne retourne que les fichiers.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#9 Le 20/02/2020, à 21:22

Fantakov

Re : [Résolu] Boucle for traitée par taille

Impeccable !

Même si c'est du bricolage ça me vas très bien pour le peu que j'en aurait besoin.
C'est surtout que si je ne l'utilise pas à nouveau avant quelques mois j'éviterais de me poser des questions en voyant les erreurs.

C'est pour trier des fichiers récupérés avec photorec donc ils sont tous nommés sans espaces ni caractères spéciaux du type "f134534354.jpg"

Encore merci à vous pour l'aide !

Hors ligne

#10 Le 20/02/2020, à 21:36

Watael

Re : [Résolu] Boucle for traitée par taille

c'est "pédagogique".
quand de futurs lecteurs chercheront une méthode pour faire la même chose dans un contexte différent, il auront une méthode sûre.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#11 Le 20/02/2020, à 23:34

kamaris

Re : [Résolu] Boucle for traitée par taille

Une autre manière de faire : laisser xargs faire les paquets de 1000 fichiers, et donc esquiver la boucle while de lecture du flux, mais au prix d'un mini-script.
J'ai inversé le sens du sort pour bien correspondre à la demande en #1, comme le fait le ls -S (malgré toutes ses imperfections).

find ./ -maxdepth 1 -type f -printf '%s %p\0' | sort -z -k1,1nr | xargs -0 -L1000 bash -c 'i=""; while test -d "img$i"; do ((i++)); done; mkdir "img$i"; mv -t "img$i" "${@#* }"' _

---

NB : sur certains systèmes, il peut y avoir une limitation au niveau du nombres de mots que peut contenir une ligne de commande.
Si la commande ci-dessus dépasse ce nombre, il faut passer moins d'arguments à la fois par xargs, et complexifier un peu le mini-script pour remplir correctement les répertoires (ou réaliser un post-traitement pour regrouper les contenus de répertoires).
Mais même dans ce cas, cette manière de faire doit être significativement plus performante qu'une boucle while (même si on y regroupait les appels à mv, au lieu d'en faire un par fichier à déplacer).

Dernière modification par kamaris (Le 21/02/2020, à 00:50)

Hors ligne