Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

This question already has an answer here:

I have a directory full of files. I want to rename all the files that match *.py to -backup.py. How do I do that.

I know I can use for i in *.py, but from there I'm not sure how to keep the initial name and just append backup to all of them.

share|improve this question

marked as duplicate by jasonwryan, Hauke Laging, Gilles, Chris Down, Mat Jul 3 '13 at 6:39

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

3 Answers 3

for i in *.py
do
    mv "$i" `echo "$i" | sed 's/\.py$/-backup.py/'`
done
share|improve this answer
    
Thanks for the help. Not to impose, but could you also explain what's going on so I can implement similar solutions when this problem comes across? –  dasElevator Jul 2 '13 at 20:06
    
Interesting...I might have used something with find so that on a HUGE directory I would hit the command line length limit. –  mdpc Jul 2 '13 at 20:28
    
@dasElevator The for statement picks one file at a time that matches your criterion (.py extension) in the directory. The mv statement renames it. The last part of the mv uses sed to generate the name as per your specs. –  unxnut Jul 2 '13 at 20:32

The essence of this is the same as unxnut's answer, but I think using sed for something as simple as stripping an extension is way overkill:

for f in ./*.py; do mv "$f" "${f%.py}-backup.py"; done

${f%.py} is the variable $f, with the .py stripped from the end. You can also remove things from the beginning with ${f#whatever}. For recursiveness (i.e. working in the current directory and all subdirectories), assuming you have bash 4+, you can use globstar:

shopt -s globstar
for f in ./**/*.py; do mv "$f" "${f%.py}-backup.py"; done

Alternatively, you can use rename -- there are actually two different programs that use this name, and which one you have will depend on your flavour of *nix. perl-rename (used by Debian and its derivatives, such as Ubuntu, and many others):

rename 's/\.py$/-rename.py/' ./*.py

The other rename would use this syntax:

rename .py -backup.py ./*.py

The for loop with mv is more portable, of course: the first, non-recursive one is POSIX, and so will work on every *nix anywhere, except maybe some museum pieces.

share|improve this answer

The same as evilsoup with find:

find . -name '*.py' -exec bash -c 'mv "$0" "${0%.py}-backup.py"' {} \;

or if you don't like to launch an instance of for each file found:

find . -name '*.py' -exec bash -c 'for f; do mv "$f" "${f%.py}-backup.py"; done' _ {} +

The find solution might be better if you have a huge number of files, since globbing is slow. Feel free to add an -n option to mv (no clobber) or a -v option (verbose).

share|improve this answer
    
More importantly than globbing being slow vs find (though ideally I'd like to see something backing that up), if you are working with a truly huge number of files, with globs you may run into the maximum number of arguments for bash. So if you're working with many hundreds of thousands of files, this is the way to go. (You can find out what the maximum number of arguments is on your system with echo "$(getconf ARG_MAX)/4-1" | bc). This is also POSIX (or it would be, if you replaced bash -c with sh -c), whereas globstar isn't. –  evilsoup Jul 2 '13 at 22:05

Not the answer you're looking for? Browse other questions tagged or ask your own question.