Por que o GNU paralelo não funciona com "bash -c"?

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


%

Eu esperaria que a segunda linha aja da mesma maneira.

Raitis Veinbahs
fonte

Respostas:

11

parallelexecuta o comando em um shell já (que desembolsar é é determinada pelo parallelusando heurística (a intenção de ser para invocar o mesmo shell como o parallelfoi invocada a partir ). Você pode definir a $PARALLEL_SHELLvariável para corrigir o shell).

Não é um comando que você está passando parallelcomo faria para o comando envou xargs, mas uma linha de comando do shell (como você faria para o evalcomando).

Como por eval, em parallel arg1 arg2, parallelestá concatenando esses argumentos com espaços no meio (assim torna-se arg1 arg2) e essa sequência é passada para <the-shell> -c.

Para os argumentos passados ​​no parallelstdin do, parallelcite-os no formato esperado por esse shell em particular (uma tarefa difícil e propensa a erros, e é por isso que você encontrará muitos bugs corrigidos em torno disso no parallelChangelog ( alguns ainda não foram corrigidos em 06/03/2017)) e o anexam a essa linha de comando.

Por exemplo, se chamado de dentro bash,

echo "foo'bar" | parallel echo foo

Teria chamada paralela bash -ccom echo foo foo\'barcomo a linha de comando. E se chamado de dentro rc(ou com PARALLEL_SHELL=rc) rc -ccom echo foo foo''''bar.

Na tua:

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

parallel concatena os argumentos que dão:

bash -c echo :$1  {}

E com o {}expandido e citado no formato certo para o shell do qual você está ligando parallel, passa o <that-shell> -cque será chamado bash -c echocom :$1in $0e o argumento atual in $1.

Não é assim que parallelfunciona. Aqui, você provavelmente desejaria:

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

Para ver o que parallelfaz, você pode executá-lo em strace -fe execve(ou equivalente no seu sistema, se não no Linux).

Aqui, você pode usar o GNU em xargsvez de parallelobter um processamento mais simples mais próximo do que você está esperando:

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

Veja também a discussão em https://lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html

Observe que bash -c 'echo foo' '' foo, você está criando $0a string vazia para esse script embutido. Eu evitaria isso, pois isso $0também é usado em mensagens de erro. Comparar:

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

com.

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

Observe também que deixar variáveis ​​sem aspas tem um significado muito especial bashe echogeralmente não pode ser usado para dados arbitrários.

Stéphane Chazelas
fonte
4
Mon dieu! Esta é uma resposta melhor do que o autor do GNU Parallel poderia ter escrito.
precisa