Dlaczego GNU równolegle nie działa z „bash -c”?


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


%

Spodziewałbym się, że druga linia zachowa się tak samo.

Odpowiedzi:


11

paralleluruchamia polecenie w powłoce już (co shell to określa się parallelza pomocą heurystyki (będący zamiar powołać taką samą powłokę jako jedna parallelzostała wywołana z ). Można ustawić $PARALLEL_SHELLzmienną naprawić powłokę).

To nie jest polecenie, które przekazujesz, paralleltak jak w przypadku polecenia envlub xargs, ale wiersz poleceń powłoki (tak jak w przypadku evalpolecenia).

Podobnie jak evalw przypadku parallel arg1 arg2, parallelłączenie tych argumentów ze spacjami pomiędzy nimi (tak się staje arg1 arg2) i ten ciąg znaków jest przekazywany do <the-shell> -c.

W przypadku argumentów przekazywanych na parallelstandardowe wejście, parallelprzytacza je w formacie oczekiwanym przez tę konkretną powłokę (zadanie trudne i podatne na błędy, dlatego odkryto, że naprawiono wiele błędów wokół tego w paralleldzienniku zmian ( niektóre nadal nie są naprawione na dzień 2017-03-06)) i dołącza to do tego wiersza poleceń.

Na przykład, jeśli zostanie wywołany od wewnątrz bash,

echo "foo'bar" | parallel echo foo

Musiałby równoległego połączenia bash -cze echo foo foo\'barjak w wierszu poleceń. A jeśli zostanie wywołany z wewnątrz rc(lub z PARALLEL_SHELL=rc) za rc -cpomocą echo foo foo''''bar.

W Twoim:

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

parallel łączy te argumenty, które dają:

bash -c echo :$1  {}

Z {}rozwiniętym i cytowanym w odpowiednim formacie dla powłoki, z której dzwonisz parallel, przekazujesz to, do <that-shell> -cktórego zadzwonisz za bash -c echopomocą :$1in $0i bieżący argument w $1.

To nie tak paralleldziała. Tutaj prawdopodobnie chcesz:

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

Aby zobaczyć, co parallelrobi, możesz uruchomić go pod strace -fe execve(lub odpowiednikiem w swoim systemie, jeśli nie Linux).

Tutaj możesz użyć GNU xargszamiast paralleluzyskać łatwiejsze przetwarzanie bliższe oczekiwaniom:

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

Zobacz także dyskusję na https://lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html

Zauważ bash -c 'echo foo' '' foo, że $0wewnątrz tworzysz pusty ciąg dla tego skryptu wbudowanego. Unikałbym tego, ponieważ $0jest to również wykorzystywane w komunikatach o błędach. Porównać:

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

z.

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

Należy również pamiętać, że pozostawienie zmiennych bez cudzysłowu ma bardzo szczególne znaczenie bashi na echoogół nie można ich używać w przypadku dowolnych danych.


4
Mon dieu! To lepsza odpowiedź, niż autor GNU Parallel mógłby napisać.
Ole Tange
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.