Forum Programmation.shell Éviter les boucles avec des syntaxes de gourou

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes : aucune
3
28
oct.
2013

Salut les moules !

Pour l'instant, j'ai un script comme ça :

for f in *.JPG
do
    convert $f -verbose -resize 600x -quality 85 resized/$f
done

C'est marrant, mais j'aimerais savoir s'il existe une syntaxe de gourou qui me permettrait de faire ça en une ligne sans script, genre avec ce genre de commande :

convert * -verbose -resize 600x -quality 85 resized/*

Je vois bien que la seconde étoile fait que je me retrouve avec un problème. C'est possible de dire que la seconde étoile ne fait que prendre la même valeur que la première ?

  • # ;

    Posté par  . Évalué à 3.

    si c'est juste que tu le veux sur une seule ligne de commande, mets des points-virgules :

    for f in *.JPG; do convert $f -verbose -resize 600x -quality 85 resized/$f; done

    • [^] # Re: ;

      Posté par  (site web personnel) . Évalué à 2.

      Je sais qu'on peut presque tout faire en une seule ligne (sauf en Python qui force l'indentation :) ), mais l'idée est bien de s'affranchir de cette boucle, pour rester général.

      • [^] # Re: ;

        Posté par  . Évalué à 7.

        « find », comme développé dans les commentaires ci-dessous, est vraiment ce qu'il te faut. L'avantage étant que, du coup, ça fonctionne avec tous les shells.

        Mais pour le reste, la boucle « for » sert précisément à faire ce qui n'est pas pris en charge par les outils eux-mêmes. Il faut savoir que quand tu écris une expression globale (man 7 glob), comme une étoile seule ou n'importe quelle expression contenant des étoiles et/ou des points d'interrogation, c'est le shell qui développe l'expression avant d'appeler la commande. Essaie par exemple « echo * », ou « echo Debut * Fin ».

        Ça veut dire que la commande elle-même n'a aucun moyen de savoir a priori si tu as saisi une étoile ou si tu as manuellement entré une liste de fichiers. Cela veut dire également que ce n'est pas la commande elle-même qui fait l'analyse syntaxique des caractères jokers pour ensuite décider ou non de faire un traitement groupé. C'est juste que la plupart des commandes sont faites pour appliquer leur traitement à chacun des fichiers dont on leur passe le nom.

        • [^] # Re: ;

          Posté par  (site web personnel) . Évalué à 2.

          Hey, merci pour cette explication détaillée. En effet, je savais que c'est le shell qui fait le job d'étendre les jokers, mais je n'avais pas réfléchi au fait qu'ensuite, le programme se retrouve avec tout un tas d'arguments et ne sait pas forcément quoi en faire.

          Donc effectivement, je vais me tourner vers find, merci !

    • [^] # Re: ;

      Posté par  (site web personnel) . Évalué à 8.

      Tant qu'à faire du one-liner, on peut enlever le do et le done comme il n'y qu'une commande :

      for f in *.JPG; convert $f -verbose -resize 600x -quality 85 resized/$f
      
  • # Avec find

    Posté par  (site web personnel) . Évalué à 4.

    Un truc comme :

    find -name '*.JPG' -exec convert {} -verbose -resize 600x -quality 85 resized/{} \;
    

    Après c'est pas vraiment plus court ;)

    • [^] # Re: Avec find

      Posté par  (site web personnel) . Évalué à 4.

      Ah, en y pensant, c'est mieux de rajouter -maxdepth 1 aux options de find, sinon find va se plaindre la deuxième fois…

  • # awk ?

    Posté par  (Mastodon) . Évalué à -3.

    Faire un peu de magie avec awk…

    un truc du genre
    bash
    ls * | awk 'convert {} -verbose -resize 600x -quality 85 resized/{}' | /bin/bash

    … je suis pas sûr du tout de la syntaxe …

    Bonne recherche !

  • # sh 101

    Posté par  (site web personnel) . Évalué à 7.

    Premièrement, tu peux faire ton for sur une seule ligne :

    $ for f in *.jpg ; do frob $f ; done
    

    Deuxièmement, tu peux faire des commandes de plusieurs lignes dans le shell interactif :

    $ for f in *.jpg
    > do
    > frob $f
    > done
    

    Troisièmement, le *.jpg va pauser des problèmes si tu as vraiment beaucoup d'images. Tu peux résoudre le problème en utilisant find comme mentionné ci-dessus.

    Quatrièmement, tu peux diminuer significativement le temps d'exécution en consommant plus de CPU en parallélisant le tout :

    $ find . -name '*.jpg' -print0 | xargs -0 -P 42 -I F -n 1 frob F
    

    Il y a aussi GNU Parallel qui peut être utile mais tout ce que j'en connais vient de dépèches DLFP : http://www.gnu.org/software/parallel/

    Tous ces exemples supposent l'utilisation de Bash, GNU coreutils et GNU find.

    pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

    • [^] # Re: sh 101

      Posté par  (site web personnel) . Évalué à 2.

      Tous ces exemples supposent l'utilisation de Bash, GNU coreutils et GNU find.

      Le find et le xargs d'OpenBSD ont aussi les options utilisées dans ces exemples, et je pense que ça doit être pareil pour les autres BSD. Il y a moins d'options qu'avec GNU find, mais il y en a quand même un paquet!

    • [^] # Re: sh 101

      Posté par  (site web personnel) . Évalué à 1.

      Tous ces exemples supposent l'utilisation de Bash, GNU coreutils et GNU find.

      Pas du tout efface… L'utilisation du for ... ; do .... ; done fonctionne aussi en KSH (et même en KSH 88).

  • # Magick

    Posté par  . Évalué à 9.

    S'agissant d'ImageMagick en particulier on peut faire :

    convert * -verbose -resize 600x -quality 85 -set filename:orig "%f" "resized/%[filename:orig]"
    

    Merci Internet !

  • # mogrify

    Posté par  . Évalué à 2.

    Pour les traitements par lot, j'utilise mogrify, qui fait parti d'ImageMagick. Il permet de travailler sur une série d'images sans faire de boucle. Mais il me semblait que convert le permettait également. As-tu essayé de te mettre dans le répertoire resized et de faire :

    convert ..\* -verbose -resize 600x -quality 85

    • [^] # Re: mogrify

      Posté par  . Évalué à 2.

      mogrify modifie le fichier source
      convert sauvegarde dans un fichier cible, la source, après l'avoir "convertie"

      • [^] # Re: mogrify

        Posté par  . Évalué à 2.

        mogrify modifie le fichier source

        C'est vrai si tu ne spécifies pas de répertoire de destination et que tu gardes le même format de fichier. Or si j'ai bien compris, Xinfe veut que les images retravaillées soient dans le dossier resized. Donc si tu ajoutes l'option -path resized/ à mogrify, les images iront dans resized et tes sources ne seront pas modifiées (il faut que le répertoire existe).
        D'ailleurs, il y a quelques années, c'était sur le site d'ImageMagick que j'avais lu que pour utiliser *.jpg, il valait mieux utiliser mogrify plutôt que convert et que pour utiliser convert, il était préférable d'utiliser une boucle ou find. À cause d'une histoire de consommation mémoire je crois si tu travailles sur beaucoup d'images, je ne me souviens plus des détails et j'ignore si c'est toujours d'actualité.

  • # xargs

    Posté par  . Évalué à 5.

    quelque chose comme ls *.JPG | xargs -I{} convert {} -verbose … foo/{}

    Bonus : Exécution en parallèle avec l'option -P

    Please do not feed the trolls

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.