Skip to content
Advertisement

xargs ignoring part of command after &&

I intend to get a comma separated list of files and then pass it as argument to a command using xargs.

However it seems xargs ignores the part of command after &&.

$ find */build* -printf '%h/%f,'
jenkins/build.jenkinsfile,jenkins/build-x.groovy,


$ find */build* -printf '%h/%f,' | xargs -t python3 -m coverage combine python-bridge && python3 -m coverage xml --omit
python3 -m coverage combine python-bridge jenkins/build.jenkinsfile,jenkins/build-x.groovy,
Couldn't combine from non-existent path 'jenkins/build.jenkinsfile,jenkins/build-x.groovy,'

So, the command is interpreted as:

python3 -m coverage combine python-bridge jenkins/build.jenkinsfile,jenkins/build-x.groovy,

Expected:

python3 -m coverage combine python-bridge && python3 -m coverage xml --omit jenkins/build.jenkinsfile,jenkins/build-x.groovy,

Any pointer will be a great help.

Advertisement

Answer

Meta: I wrote a much longer comment that Stack seems to have discarded somehow, so I am re-doing as an answer to get edit history even though I’m not sure this is really programming (and thus may need to be deleted).

It’s not xargs. The shell breaks that input into two commands, and then executes the first pipeline by running find */build* -printf '%h/%f,' as one process with stdout connected to a pipe and xargs -t python3 -m coverage combine python-bridge as another process with stdin connected to that same pipe; only after both of these complete, and only if the xargs is successful which in turn is only if the python3 -m ... is successful which it wasn’t, the shell would run the second command python3 -m coverage xml --omit as a third process.

You could pass the && to xargs by quoting it: any of '&&' "&&" &&. However xargs is not a shell and will not interpret the && as an ‘and’ operator; it will run one python3 process with arguments -m coverage combine python-bridge && python3 -m coverage xml --omit with the (one) input ‘filename’ jenkins/build.jenkinsfile,jenkins/build-x.groovy, appended, and that won’t work either.

You can have xargs run a shell which in turn runs the commands you want:

find */build* -printf '%h/%f,' | 
xargs -t sh -c 'python3 -m coverage combine python-bridge && python3 -m coverage xml --omit $*' dummy0'
# in general you should use "$@" to prevent split+glob from mangling 'special' arguments
# but here they have already survived xargs default parsing so shouldn't be special

But much simpler is to arrange your commands more appropriately:

python3 -m coverage combine python-bridge && 
find */build* -printf '%h/%f,' | python3 -m coverage xml --omit

or since this works correctly only if the list of files fits in one command so you don’t actually want xargs main functionality, just

python3 -m coverage combine python-bridge && 
python3 -m coverage xml --omit $(find */build* -printf '%h/%f,')
Advertisement