Warum funktioniert GNU nicht parallel mit "bash -c"?

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


%

Ich würde erwarten, dass die zweite Zeile genauso funktioniert.

Raitis Veinbahs
quelle

Antworten:

11

parallelführt den Befehl in einer Schale bereits (die Schale durch bestimmt wird , ist parallelunter Verwendung von Heuristiken (die Absicht ist , die gleiche Schale wie die aufzurufen parallelaufgerufen wurde aus ). Sie Das Set kann $PARALLEL_SHELLvariabel die Schale zu fixieren).

Es ist kein Befehl, an den Sie übergeben, parallelwie Sie es für den Befehl envoder tun würden xargs, sondern eine Shell-Befehlszeile (wie Sie es für den evalBefehl tun würden ).

Wie für eval, in parallel arg1 arg2, werden paralleldiese Argumente mit Leerzeichen dazwischen verkettet (so wird es arg1 arg2) und diese Zeichenfolge wird an übergeben <the-shell> -c.

Zitieren Sie die Argumente, die an parallelstdin übergeben werden, parallelin dem Format, das von dieser bestimmten Shell erwartet wird (eine schwierige und fehleranfällige Aufgabe, weshalb Sie feststellen werden, dass in parallelChangelog () viele Fehler behoben wurden. Einige sind bis zum 06.03.2017)) noch nicht behoben und hängen sie an diese Befehlszeile an.

So zum Beispiel, wenn von innen aufgerufen bash,

echo "foo'bar" | parallel echo foo

Hätte parallelen Anruf bash -cmit echo foo foo\'barals Kommandozeile. Und wenn von innen rc(oder mit PARALLEL_SHELL=rc) rc -cmit aufgerufen echo foo foo''''bar.

In deinem:

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

parallel verkettet die folgenden Argumente:

bash -c echo :$1  {}

Und mit dem {}erweiterten und im richtigen Format zitierten Format für die Shell, von der aus Sie aufrufen parallel, wird das übergeben, an <that-shell> -cdas bash -c echomit :$1in $0und das aktuelle Argument in aufgerufen wird $1.

So parallelfunktioniert das nicht . Hier möchten Sie wahrscheinlich:

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

Um zu sehen, was parallelfunktioniert, können Sie es unter strace -fe execve(oder dem Äquivalent auf Ihrem System, wenn nicht Linux) ausführen .

Hier könnten Sie GNU verwenden, xargsanstatt paralleleine einfachere Verarbeitung näher an das zu bringen, was Sie erwarten:

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

Siehe auch die Diskussion unter https://lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html

Beachten Sie, dass in bash -c 'echo foo' '' foo, machst du $0die leere Zeichenfolge für den Inline-Skript. Ich würde das vermeiden, da dies $0auch in Fehlermeldungen verwendet wird. Vergleichen Sie:

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

mit.

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

Beachten Sie auch, bashdass echodas Nicht- Zitieren von Variablen eine ganz besondere Bedeutung hat und im Allgemeinen nicht für beliebige Daten verwendet werden kann.

Stéphane Chazelas
quelle
4
Mon dieu! Dies ist eine bessere Antwort, als der Autor von GNU Parallel hätte schreiben können.
Ole Tange