Question

I was using a code to rename files and a very interesting problem emerged: It worked in a computer running Mac OSX Lion 10.7.5, but it failed on Mac OSX 10.6.8 Snow Leopard.

The code is:

for i in *; do mv $i `echo $i | sed 's/..//'`; done

and the error I got is:

usage: mv [-f | -i | -n] [-v] source target
   mv [-f | -i | -n] [-v] source ... directory

It's very weird because mv is working normally if not in a for loop...

Anyone know what should I do to get it working?

Was it helpful?

Solution 2

If you have files with spaces (or certain other shell metachaarcters) it's critical that you put all variable references in double-quotes. Otherwise, if you have e.g. i="File Name.txt", you'll be running a command like mv File Name.txt le Name.txt and it'll think you're specifying 4 filenames not just 2. The other standard mistake (which you're not making) is using for file in $(ls), which gets confused by spaces before the names even make it into the variable.

Also, I'm a bit concerned about short filenames and name conflicts. Even if you think you don't have any short filenames, if you have the dotglob shell option set you'll wind up trying to rename the pseudo-files "." and "..", which won't go well at all. Also, if you have e.g. files named "abcdefg" and "cdefg", the script will rename the first over the second (silently erasing the second), then rename that to "efg".

So, here's my proposed rewrite (also using @TrueY's suggestion for shortening the filename):

for i in *; do
    if [ ${#i} -le 2 ]; then
        echo "$i: not renamed (too short)" >&2
    elif [ -e "${i:2}" ]; then
        echo "$i: not renamed (${i:2} already exists)" >&2
    else
        mv "$i" "${i:2}"
    fi
done

OTHER TIPS

You should use bash string substitution:

for i in *; do mv $i ${i/??/}; done

or

for i in *; do mv $i ${i#??}; done
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top