1

I try to improve with semaphores some photo processing script I use. I run sable GNU/DEBIAN There is a function called travail that uses a given filename as an argument, and that processes the file.

For now, that function is called in the same script with a loop :

  for i in *.png ; do
    travail $i &
    done

The problem is that it uses a lot of memory if there are a lot of pictures. I would like to use semaphores to limit the number of threads.

I tried:

for i in *.png ; do
sem -j+0 travail $i
done
sem --wait

But it does not work, with the following message : /bin/bash: travail : commande introuvable (that means command not found)

I try to add export -f travail after the function has been defined, but it does not work.

Exemple of the output (2 files for this exemple)

travail sur image 113_XT1S3739.png convert-im6.q16: unable to open image x': Aucun fichier ou dossier de ce type @ error/blob.c/OpenBlob/2874. convert-im6.q16: no decode delegate for this image format' @ error/constitute.c/ReadImage/560. convert-im6.q16: invalid argument for option -quality': -unsharp @ error/convert.c/ConvertImageCommand/2460. composite-im6.q16: invalid argument for option-quality': sortie/grand_format/ne_pas_publier_113_XT1S3739.jpg @ error/composite.c/CompositeImageCommand/1241. travail sur image 113_XT1S3779.png convert-im6.q16: unable to open image x': Aucun fichier ou dossier de ce type @ error/blob.c/OpenBlob/2874. convert-im6.q16: no decode delegate for this image format' @ error/constitute.c/ReadImage/560. convert-im6.q16: invalid argument for option -quality': -unsharp @ error/convert.c/ConvertImageCommand/2460. composite-im6.q16: invalid argument for option-quality': sortie/grand_format/ne_pas_publier_113_XT1S3779.jpg @ error/composite.c/CompositeImageCommand/1241. etc.

For more information, Here is the script

   # !/bin/bash
    # _____________________________ Paramètres
    T_WEB="1000"   # Taille maxi des images pour le web
    Q_WEB="100"   # Qualité des images pour le web (100 car il faut les réouvrir pour mettre le logo)
    #
    H_MOY="1795"   # Hauteur maxi des images pour impression ?x15
    L_MOY_11="1347"  # Largeur maxi des images pour impression 11x15
    L_MOY_10="1204"  # Largeur maxi des images pour impression 10x15
    Q_MOY="96"   # Qualité des images pour impression 10x15
    #
    Q_GRA="99"   # Qualité des grandes images
    #
    B_INT="0.1%"   # Taille de la bordure intérieure
    B_CEN="0.3%"   # Taille de la bordure intérieure
    B_EXT="4%"   # Taille de la bordure extérieure
    C_INT="white"   # Couleur de la bordure intérieure
    C_CEN="black"   # Couleur de la bordure intérieure
    C_EXT="white"   # Couleur de la bordure extérieure
    #
    # __________________________________________________________________
    #
    # Fonction principale
    #
    function travail
    {
    # Lecture du nom de fichier à traiter
    local f=$1
    echo 'travail sur image' $f
    # Récupération d'infos sur l'image en cours
    local LARG=`convert -quiet -ping $f -format "%w" info:`
    local HAUT=`convert -quiet -ping $f -format "%h" info:`
    local LARG=${LARG:0:4} # On ne conserve que les 4 premiers chiffres, le reste n'est pas bon
    local HAUT=${HAUT:0:4}
    local DECALE_X=$(($LARG/24))
    local DECALE_Y=$(($HAUT/22))
    #
    # Récupération du nom du fichier et de l'extension
    local nomfichier="${f%%.*}"
    #
    # Recuperation donnees EXIF (elles sont écrites dans un fichier temporaire)
    if [ -f "${nomfichier}.RAF" ]
    then
     exiv2 -q ex ${nomfichier}.RAF
    fi
    if [ -f "${nomfichier}.NEF" ]
    then
     exiv2 -q ex ${nomfichier}.NEF
    fi
    #
    # Ajout des bordures
    convert $f -quiet -bordercolor ${C_INT} -border ${B_INT}  -bordercolor ${C_CEN} -border ${B_CEN} -bordercolor ${C_EXT} -border ${B_EXT}x${B_EXT} -quality 01 /tmp/$f
    #
    # Création image WEB
    convert /tmp/$f -resize ${T_WEB}x${T_WEB} -quality ${Q_WEB} -unsharp 3 sortie/web/${nomfichier}_pour_internet.jpg
    if [ -f "${nomfichier}.NEF" ]
    then
     mv ${nomfichier}.exv sortie/web/${nomfichier}_pour_internet.exv
     exiv2 in sortie/web/${nomfichier}_pour_internet.jpg
     exiftool -Orientation=1 -n sortie/web/${nomfichier}_pour_internet.jpg
     rm sortie/web/${nomfichier}_pour_internet.jpg_original
    fi
    #
    # Ajout logo puis conversion en JPG
    composite -compose Over -geometry +$DECALE_X+$DECALE_Y -gravity SouthEast /home/pierre/Documents/Photo/baniere-logo/logo_800x600.png /tmp/$f -quality ${Q_GRA} sortie/grand_format/ne_pas_publier_${nomfichier}.jpg
    #
    if [ -f "${nomfichier}.NEF" ]
    then
     mv sortie/web/${nomfichier}_pour_internet.exv sortie/grand_format/ne_pas_publier_${nomfichier}.exv
     exiv2 in sortie/grand_format/ne_pas_publier_${nomfichier}.jpg
     exiftool -Orientation=1 -n sortie/grand_format/ne_pas_publier_${nomfichier}.jpg
     rm sortie/grand_format/ne_pas_publier_${nomfichier}.jpg_original
     rm sortie/grand_format/ne_pas_publier_${nomfichier}.exv
    fi
    # Suppression des fichiers inutiles
    rm /tmp/$f
    if [ -f "${nomfichier}.RAF" ]
    then
     rm ${nomfichier}.exv
    fi
    }
    #
    # _____________________________ Création des dossiers et préparation ___________________________________________
    if test -e sortie; then
    rm -rf sortie
    fi
    mkdir sortie
    mkdir sortie/web
    mkdir sortie/grand_format
    #
    # _____________________________ Appel de la fonction en parallèle sur toutes les images PNG
    #
    #
    for i in *.png ; do
             travail $i &                                                                 
    done 
    wait
    #
    # _____________________________ Fin de la fonction ________________________________________________________
    #
    echo
    echo TERMINÉ
Pierre
  • 11
  • 1
    sem can only execute external programs, not shell functions (or aliases). rewrite your travail function as a shell script and make it executable. run sem -j+0 /path/to/travail.sh – cas Aug 29 '19 at 16:14
  • it might be worth defining travail in your .bashrc or .bash_profile (i don't know if it sources either or both of them or not). but there's little or no benefit over just putting it in standalone sccript. – cas Aug 29 '19 at 16:18
  • I would prefer having a single script file than using a travail script and another script to prepare the directories and call it. Is it a way to parallelise a function ? – Pierre Aug 29 '19 at 16:23
  • another thing to try: sem -j+0 bash -c "travail $i" (this, if it works, would require travail to be exported, or defined in .bashrc). – cas Aug 29 '19 at 16:26
  • See also https://unix.stackexchange.com/q/235155/117549 – Jeff Schaller Aug 29 '19 at 16:31
  • sem -j+0 bash -c "travail $i" gives me : travail sur image convert-im6.q16: no images defined info:' @ error/convert.c/ConvertImageCommand/3258. convert-im6.q16: no images definedinfo:' @ error/convert.c/ConvertImageCommand/3258. environment: ligne 6: /24 : erreur de syntaxe : opérande attendu (le symbole erroné est « /24 ») – Pierre Aug 29 '19 at 16:34
  • Jeff, thats a nice workaround. In my case the number of file is variable from 2 to 100+ I already have a workaround : if the memory is used more than 50% I set the scritp to sleep for some time – Pierre Aug 29 '19 at 16:36
  • @Pierre i can pass args to a shell script with bash -c, but it seems that a function just ignores them. sem ./foo.sh 1 2 3 4 5 works (i.e. foo.sh, which just has echo foo "$@" prints foo 1 2 3 4 5) . sem bash -c 'foo "$@"' bash 1 2 3 4 5 just prints foo. foo is an exported function foo () { echo foo "$@";}; export -f foo. odd. if i wasn't falling asleep at my kb i'd investigate some more. – cas Aug 29 '19 at 16:57
  • Yes, it seems that it ignores the argument. You may go to bed, dont worry. My script is working, i just want to improve it and to learn. – Pierre Aug 29 '19 at 17:05

0 Answers0