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

6,888

Solution 1

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.

Solution 2

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 {} +

Solution 3

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 ".

Share:
6,888

Related videos on Youtube

Harv
Author by

Harv

Updated on September 18, 2022

Comments

  • Harv
    Harv over 1 year

    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.

    • Barmar
      Barmar over 9 years
      Does your system have the rename command that uses regular expressions to rename by patterns?
    • Harv
      Harv over 9 years
      @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?
    • Barmar
      Barmar over 9 years
      Yes, that's it.
  • Harv
    Harv over 9 years
    That worked. Can you expand your answer to explain why, and if it's possible to do this without rename?
  • Harv
    Harv over 9 years
    Aha, cool. That helps me understand why it didn't work, thanks.