3

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.

  • Does your system have the rename command that uses regular expressions to rename by patterns? – Barmar Dec 8 '14 at 22:31
  • @Barmar no, but it looks like I could grab a copy using homebrew - rename version 1.6 from plasmasturm.org/code/rename. Is that what you're referring to? – Harv Dec 8 '14 at 22:33
  • Yes, that's it. – Barmar Dec 8 '14 at 22:34
5

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.

  • That worked. Can you expand your answer to explain why, and if it's possible to do this without rename? – Harv Dec 8 '14 at 22:35
  • You might want to replace echo "$0" by printf "%s" "$0" to avoid issues with file names starting with a dash or containing an escaped character. – jlliagre Dec 9 '14 at 12:32
3
xargs -0 -I {} mv {} {} | tr -d \"

doesn't make sense: mv doesn't produce output. Thus you cannot build pipelines with mv.

find . -name '*"*' -exec bash -c 'mv "$1" "${1//\"/}"' bash {} \;

or with less overhead

find . -name '*"*' -exec bash -c 'for file in "$@"; do mv "$file" "${file//\"/}"; done' bash {} +
  • Aha, cool. That helps me understand why it didn't work, thanks. – Harv Dec 8 '14 at 23:41
1

You might do...

mkdir ../_cp
pax -Xwrl -s'/"//gp' . "${PWD%/*}/_cp"

That just creates a bunch of hardlinks to all files in the hierarchy rooted at . in ../_cp. You can then verify everything is well with both directories before removing one of them - they are pretty much the same directories after all, except in one directory there are no filenames which contain a ".

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.