Prevent GNU parallel from splitting quoted arguments

command linegnu-parallelquoting

I'm trying to use GNU Parallel to run a comman mutliple times with a combination of constant and varying arguments. But for some reason the constant arguments are split on white-space even though I've quoted them when passing them to parallel.

In this example, the constant argument 'a b' should be passed to debug-call as a single argument instead of two:

$ parallel debug-call 'a b' {} ::: {1..2}
[0] = '[...]/debug-call'
[1] = 'a'
[2] = 'b'
[3] = '1'
[0] = '[...]/debug-call'
[1] = 'a'
[2] = 'b'
[3] = '2'

debug-call is a simple script which prints each argument it has been passed in argv. Instead I would expect to see this output:

[0] = '[...]/debug-call'
[1] = 'a b'
[2] = '1'
[0] = '[...]/debug-call'
[1] = 'a b'
[2] = '2'

Is this a bug or is there a option to prevent GNU Parallel from splitting command line arguments before passing them on to the command?

Best Answer

parallel runs a shell (which exact one depending on the context in which it is called, generally, when called from a shell, it's that same shell) to parse the concatenation of the arguments.

So:

parallel debug-call 'a b' {} ::: 'a b' c

is the same as

parallel 'debug-call a b {}' ::: 'a b' c

parallel will call:

your-shell -c 'debug-call a b <something>'

Where <something> is the arguments (hopefully) properly quoted for that shell. For instance, if that shell is bash, it will run

bash -c 'debug-call a b a\ b'

Here, you want:

parallel 'debug-call "a b" {}' ::: 'a b' c

Or

parallel -q debug-call 'a b' {} ::: 'a b' c

Where parallel will quote the arguments (in the correct (hopefully) syntax for the shell) before concatenating.

To avoid calling a shell in the first place, you could use GNU xargs instead:

xargs -n1 -r0 -P4 -a <(printf '%s\0' 'a b' c) debug-call 'a b'

That won't invoke a shell (nor any of the many commands ran by parallel upon initialisation), but you won't benefit from any of the extra features of parallel, like output reordering with -k.

You may find other approaches at Background execution in parallel