Pourquoi le parallèle GNU ne fonctionne-t-il pas avec «bash -c»?

9
% echo -e '1\n2' | parallel "bash -c 'echo :\$1' '' {}"
:1
:2
% echo -e '1\n2' | parallel bash -c 'echo :\$1' '' {}


%

Je m'attendrais à ce que la deuxième ligne agisse de la même façon.

Raitis Veinbahs
la source

Réponses:

11

parallelexécute déjà la commande dans un shell (de quel shell il s'agit, déterminé à l' parallelaide d'heuristiques (l'intention étant d'appeler le même shell que celui à partir duquel vous avez parallelété invoqué ). Vous pouvez définir la variable pour corriger le shell).$PARALLEL_SHELL

Ce n'est pas une commande que vous passez parallelcomme vous le feriez pour la commande envou xargs, mais une ligne de commande shell (comme vous le feriez pour la evalcommande).

Comme pour eval, dans parallel arg1 arg2, parallelconcatène ces arguments avec des espaces entre les deux (donc cela devient arg1 arg2) et cette chaîne est passée à <the-shell> -c.

Pour les arguments qui sont passés sur parallelstdin, les parallelcite dans le format attendu par ce shell particulier (une tâche difficile et sujette aux erreurs, c'est pourquoi vous constaterez qu'il y a eu beaucoup de bugs corrigés autour de cela dans parallelle journal des modifications ( certains ne sont toujours pas corrigés au 06/03/2017)) et l'ajoutent à cette ligne de commande.

Ainsi, par exemple, s'il est appelé de l'intérieur bash,

echo "foo'bar" | parallel echo foo

Aurait un appel parallèle bash -cavec echo foo foo\'barcomme ligne de commande. Et s'il est appelé de l'intérieur rc(ou avec PARALLEL_SHELL=rc) rc -cavec echo foo foo''''bar.

Dans ton:

parallel bash -c 'echo :\$1' '' {}

parallel concatène les arguments qui donnent:

bash -c echo :$1  {}

Et avec le {}développé et cité dans le bon format pour le shell à parallelpartir <that-shell> -cduquel vous appelez , passe ce à qui appellera bash -c echoavec :$1in $0et l'argument actuel dans $1.

Ce n'est pas comme ça que ça parallelmarche. Ici, vous voudriez probablement:

printf '1\n2\n' | PARALLEL_SHELL=bash parallel 'echo :{}'

Pour voir ce qui se parallelpasse, vous pouvez l'exécuter sous strace -fe execve(ou l'équivalent sur votre système si ce n'est Linux).

Ici, vous pouvez utiliser GNU xargsau lieu de parallelrapprocher un traitement plus simple de ce que vous attendez:

printf '1\n2\n' | xargs -rn1 -P4 bash -c 'echo ":$1"' ''

Voir également la discussion sur https://lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html

Notez que dans bash -c 'echo foo' '' foo, vous créez $0la chaîne vide pour ce script en ligne. J'éviterais cela car cela $0est également utilisé dans les messages d'erreur. Comparer:

$ bash -c 'echo x > "$1"' '' /
: /: Is a directory

avec.

$ bash -c 'echo x > "$1"' bash /
bash: /: Is a directory

Notez également que laisser des variables sans guillemets a une signification très spéciale dans bashet qui echone peut généralement pas être utilisé pour des données arbitraires.

Stéphane Chazelas
la source
4
Mon dieu! C'est une meilleure réponse que l'auteur de GNU Parallel aurait pu écrire.
Ole Tange