4

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.

3
  • Does your system have the rename command that uses regular expressions to rename by patterns?
    – Barmar
    Dec 8, 2014 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, 2014 at 22:33
  • Yes, that's it.
    – Barmar
    Dec 8, 2014 at 22:34

3 Answers 3

6

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.

2
  • That worked. Can you expand your answer to explain why, and if it's possible to do this without rename?
    – Harv
    Dec 8, 2014 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, 2014 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 {} +
1
  • Aha, cool. That helps me understand why it didn't work, thanks.
    – Harv
    Dec 8, 2014 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 ".

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .