Por que o trabalho paralelo do GNU com o “bash -c”?

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


%

Eu esperaria que a segunda linha agisse da mesma forma.

    
por Raitis Veinbahs 06.03.2017 / 14:02

1 resposta

9

parallel executa o comando em um shell (cujo shell é determinado por parallel usando heurística (a intenção é invocar o mesmo shell que o parallel foi invocado de ). Você pode definir a variável $PARALLEL_SHELL para corrigir o shell.

Não é um comando que você está passando para parallel , como faria com o comando env ou xargs , mas com uma linha de comando do shell (como você faria com o comando eval ).

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

Para os argumentos que são passados no stdin de parallel , parallel os cita no formato esperado por aquele shell específico (uma tarefa difícil e propensa a erros, e é por isso que você verá que tem havido muita erros corrigidos em torno do Changelog do parallel ( alguns são ainda não corrigido a partir de 2017-03-06)) e o anexa a essa linha de comando.

Então, por exemplo, se chamado de bash ,

echo "foo'bar" | parallel echo foo

Teria uma chamada paralela bash -c com echo foo foo\'bar como linha de comando. E se chamado de rc (ou com PARALLEL_SHELL=rc ) rc -c com echo foo foo''''bar .

Na sua:

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

parallel concatena os argumentos que fornecem:

bash -c echo :$1  {}

E com o {} expandido e cotado no formato correto para o shell do qual você está chamando parallel , passa para <that-shell> -c , que chamará bash -c echo com :$1 in $0 e argumento atual em $1 .

Não é como parallel funciona. Aqui, você provavelmente desejaria:

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

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

Aqui, você pode usar o GNU xargs em vez de parallel para obter um processamento mais simples mais próximo do que você espera:

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

Veja também a discussão no link

Observe que, em bash -c 'echo foo' '' foo , você está transformando $0 a string vazia para esse script inline. Eu evitaria isso, pois $0 també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 em bash e que echo geralmente não pode ser usado para dados arbitrários.

    
por 06.03.2017 / 14:30