i was using find . -type f -print0 | xargs -0 sh -c to execute series of commands like this

find . -type f \
exec grep -q `filter` \
-print0 | xargs -0 sh -c '
sed -i.bak s/this/that/g ${0}
git diff --no-index /path/to/${0}.bak /path/to/${0} >> my.patch
rm ${0}.bak

this looks like search&replace, backup, patch, remove backup, but when i look at the patch file, most changes are not there, so i tried a different way

find . -type f \
exec grep -q `filter` \
-print0 | xargs -0 sed -i.bak s/this/that/g {} \;

after that, i move all .bak files to a backup folder, this time, i can see there're many files changed, and patch file generated based on backup and source folder is much bigger

i'm ok with the second approach, i just want to know where i did wrong in first approach, why not all commands were executed inside sh -c? thanks!


xargs will try to run the command with as many arguments as it can, but you're only using one of those. Something like the following would process all arguments:

xargs -0 sh -c '
for i
sed -i.bak s/this/that/g "$i"
git diff --no-index /path/to/"$i".bak /path/to/"$i" >> my.patch
rm "$i".bak
' _ 

for i (or for i in "$@") will loop over every argument (except $0), so it's easier to have something like _ be $0 instead and not use $0 at all.

  • wow, thanks a lot, your solution works perfectly
    – jerry
    Mar 18 at 5:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.