Utiliser parallel dans un script bash

Tags: #<Tag:0x00007f4e400b4380> #<Tag:0x00007f4e400b4268>

Bonjour.

J’essaye d’utiliser l’outil parallel dans un script bash, dont le but est le déploiement du répertoire public d’un site fait avec le SGG Hugo.
Voici le script : PrivateBin

Dans la fonction _compress, je n’arrive pas à comprendre comment utiliser parallel pour mettre en parallèle l’appel à deux autres fonctions.

Function _compress() :

# Compress all thoses datas files. .eot, .otf and .ttf are font files
_compress() {

    cd "${dir_local}" || exit 1
    find . -type f -size +1024c -a \( \
        -name "*.eot" -o -name "*.html" \
        -o -name "*.otf" -o -name "*.svg" -o -name "*.ttf" \
        -o -name "*.txt" -o -name "*.xml" \
        \) | while read -r line;
        do echo "Compress ${line}";
            #find . ! -newer "${line}" | parallel -j "${nproc}" _brotli _gz;
            find . ! -newer "${line}" | _brotli & _gz;
            #find . ! -newer "${line}" | _brotli; _gz;
        done
    cd "$ROOT" || exit 1

}

Dans l’état actuel, la commande fonctionne bien ; elle exécute les deux commandes _brotly et _gz en parallèle, mais c’est du « parallélisme » fait par le système.

Si je commente la ligne fonctionnelle pour décommenter celle concernant l’utilisation du binaire parallel, lors de l’exécution le script me retourne que les commandes appelées n’existent pas !
Hors, elles existent bel et bien dans le script.

J’ai essayé de trouver des informations concernant l’usage de l’outil parallel appelant n-function, mais je n’en trouve pas dans le contexte de script bash.

Peut-être que quelqu’un ici a une idée pertinente ?!
Merci d’avance.

Bonjour,

Merci de m’avoir fait redécouvrir parallel.

Ci-dessous un petit exemple.

#!/usr/bin/bash

# https://stackoverflow.com/a/4321522

funcA() {
        printf -- 'starting job A\n'
        sleep 3
        printf -- 'job A terminating\n'
}
export -f funcA 

funcB() {
        printf -- 'starting job B\n'
        sleep 2
        printf -- 'job B terminating\n'
}
export -f funcB 

time -- find / -name passwd -print0 2>/dev/null | \
        parallel --jobs 100 --ungroup -0 --quote -- ::: funcA funcB :::: -


AnonymousCoward

OK, déjà merci pour ta réponse.

Donc, si je comprend bien, en premier tu exportes la fonction XYZ, puis la suivante pour pouvoir l’appeler en argument de l’outil parallel.

Je viens de trouver le fichier pdf parallel_examples ; et je n’avais pas vu les exports dans ton script d’exemples, avant de le lire dans ledit fichier.
Bon, je vais m’atteler à comprendre les autres symboles déclarés en tant qu’arguments de l’outil.

Oui, il faut d’abord exporter la fonction. Puis lancer un bash qui appelle la fonction :
bash -c '{} "{}"' , qui avec le remplacement des paires d’accolades par les arguments devient bash -c 'funcA "/etc/passwd"' .

C’est ce lien qui m’a donné la solution : https://stackoverflow.com/a/4321522


AnonymousCoward

Je suis entrain de potasser le document GNU_Parallel de 2018, en même temps :stuck_out_tongue:

Mais si je comprend bien le chapitre EXAMPLE: Calling Bash functions du document parallel_examples, cité ci-dessus, il n’y a pas besoin de déclarer bash -c '{} "{}".
L’export de la fonction est un premier pas ; ensuite l’appel à la fonction se fait très simplement.

Exemple donné :

doit() {
    … n instructions
}
export -f doit
parallel doit ::: 1 2 3

doubleit() {
    … z instructions
}
export -f doubleit
parallel doubleit ::: 1 2 3 ::: a b
1 J'aime

Oui, tu as tout à fait raison pour l’appel à la fonction.
Il faut par contre rajouter --quote au cas où le chemin du fichier contiendrait un séparateur.

Exemple modifié.


AnonymousCoward

Bon, il semble que j’y arrive en ayant modifié ainsi :

_parallel_cmprs() {

    cd "${dir_local}" || exit 1

    find . -type f -size +1024c -a \( \
        -name "*.eot" -o -name "*.html" \
        -o -name "*.otf" -o -name "*.svg" -o -name "*.ttf" \
        -o -name "*.txt" -o -name "*.xml" \
        \) | parallel -j "${nproc}" "echo Compress {}; brotli-rs -c -efficient -q11 {} {}.br; pigz -9 -k {}"

    cd "$ROOT" || exit 1

}

En effet, la section ‹ EXAMPLE: Rewriting a for-loop and a while-read-loop › m’a permis de comprendre que je pouvais faire bien plus simple que de passer par une boucle ‹ find | while read loop › !
parallel est vraiment un outil puissant.