xargs: command substitution $(...) with pipe doesn't work

Solution 1:

The for loop answer is exactly what I didn't come here to read. The whole purpose of xargs is avoiding this loop. xargs might not be the smartest tool for this particular case, but the question was about it.

Here is the solution I ended up with. It's probably not perfect, but works nevertheless :

echo "aaa111 bbb111" | xargs -I {} sh -c "echo \$(echo {} | sed 's/111/222/g')"
# Outputs aaa222 bbb222

You can come up with different variants of the same command :

echo "aaa111 bbb111" | xargs -I {} sh -c 'echo $(echo {} | sed "s/111/222/g")'
echo "aaa111 bbb111" | xargs -I {} sh -c "echo \`echo {} | sed 's/111/222/g'\`"

The main point here is just to invoke a new shell that will do the command substitution after xargs has replaced the replace-str(here {}) with the right content.

Solution 2:

$(echo {} | sed 's/111/222/g') is evaluated before it's passed to xargs as parameter. It will return {}.

Hence:

echo "aaa111 bbb111" | xargs -I {} echo $(echo {} | sed 's/111/222/g')

is the same as

echo "aaa111 bbb111" | xargs -I {} echo {}