Bash – find, xargs and mv: renaming files with double-quotes, expansion and bash precedence issue

bashfindshell-scriptxargs

Ok, I'm simply trying to strip out double-quotes in my filenames. Here's the command I came up with (bash).

$ find . -iname "*\"*" -print0 | xargs -0 -I {} mv {} {} | tr -d \"

The problem is the 'mv {} {} | tr -d \"' part. I think it's a precedence problem: bash seems to be interpreting as (mv {} {}) | tr -d \"), and what I'm left with are both filenames stripped of double-quotes. That's not what I want, obviously, because then it fails to rename the file. Instead, I want the first filename to have the quotes, and the second not to, more like this: mv {} ({} | tr -d \").

How do I accomplish this? I've tried brackets and curly braces, but I'm not really sure what I'm doing when it comes to explicitly setting command execution precedence.

Best Answer

Assuming you have the rename command installed, use:

find . -name '*"*' -exec rename 's/"//g' {} +

The rename command takes a Perl expression to produce the new name. s/"//g performs a global substitution of the name, replacing all the quotes with an empty string.

To do it with mv you need to pipe to a shell command, so you can execute subcommands:

find . -name '*"*' -exec sh -c 'mv "$0" "$(printf %s "$0" | tr -d "\"")"' {} \;

What you wrote pipes the output of xargs to tr, it doesn't use tr to form the argument to mv.