Inspired by this question. The original question, in short, is "How to turn all :2f into - in all files within a folder". e.g. If I have a file ./abc:2fdef it should be renamed into ./abc-def.

At first I thought it to be a simple task... find all files and then sed to replace :2f into -. When trying to construct a one-liner, I come up with the command:

find . -type f -name '*:2f*' | xargs -I {} mv {} $(echo {} | sed "s/:2f/-/ig")

However it doesn't work. After doing lots of testing, I found that the problem lays at the xargs part - $() was executed before xargs place substitute {} with the file names. To elaborate,

xargs -I {} mv {} $(echo {} | sed "s/:2f/-/ig")

was evaluated as ($(...) was evaluated)

xargs -I {} mv {} {}

and then

mv ./abc:2fdef ./abc:2fdef

Which was not that I am expecting. So, my question is, can I make xargs substitute all {} into filenames before evaluating the $(...) part?


No, because xargs can't substitute something before the shell calls xargs with $(…) already evaluated. This is due to the order of shell expansion.

I would probably do it like so:

find . -type f -name '*:2f*' -exec bash -c 'mv -- "$0" "${0//:2f/-}"' {} \;

Here, the shell call is evaluated from every file found by find, and the string replacement is done with shell features rather than another call to sed.

Also, this approach is safer because spaces in filenames are properly handled (through double-quoting the arguments to the mv call). More about that here.

For these tasks you probably want a more efficient tool like zmv, which is available in Zsh, or the Perl rename, which is bundled with many Linux distributions:

rename 's/:2f/-/' *
  • +1 for "order of shell expansion" and "string replacement as shell features". Thanks! – Kenneth L Jul 17 '14 at 2:25

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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