Xargs

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the unix category.

Last Updated: 2022-05-26

How to pass dynamic line-based arguments when using xargs

$ ag "function " resources/js | xargs -I {} ag {} resources/views

How to run multiple commands on each arg with xargs

$ ag "function " resources/js |  xargs -I {}  sh -c "echo {}\n; ag {} resources/views && echo 'found'"

How to continue xargs loop even though one iteration failed

By default this happens except for exist code 255. To get around this exception, do the following:

$ xargs sh -c "somecommand || true"

How to prevent xargs from continuing even though one iteration failed

Exit with 255 in a sh -c process using || after the risky command

find . -name "package.json" -type f -maxdepth 2 |  xargs -I{} sh -c '(git -C {} pull || exit 255)'

Though, it might be easier to use find -exec where applicable

$ find app/views -iname *html.erb -exec htmlbeautifier -e -b 1 {} \;

Remember: Xargs is greedy

When I ran wc on the piped output of xargs like so

$ find . -name "*.md" | xargs wc

64     416    2745 ./audio-checklist.md
23     111     776 ./README.md
59     382    2307 ./preparation-checklist.md
2890   15333   96605 total

I saw in the output both the word counts for individual files and a total.

The individual entries are expected. But why the total?

The reason is because xargs passes the "input command" (wc here) as many arguments as the input command can take. Therefore this is equivalent to wc **/*.md, which produces EXACTLY the same output. I.e. the totaling comes from wc, not xargs. I.e. xargs takes as many args as possible (vs. 1 at a time)

To get rid of the total, tell xargs to pass one argument at a time

find . -name "*.md" | xargs -n 1 wc