Rename/copy files using Python code
Project description
Abstract
This package provides a command line utility called aka for swiftly renaming (or copying) files using Python code. This makes it easy to rename files even when the changes you are making are quite complicated. It always renames files in two passes to avoid collisions; it tries to detect miscellaneous errors in advance; and if errors occurs underways it will put you in an emergency mode to resolve the problem or roll back changes. It also provides the functions aka.rename and aka.copy, which is the underlying interface.
The problem being solved
Lets say you have a directory with the files File0, File1, and File2. Then some people comes along and complains (rightly or wrongly) that the numbering starts at zero. So you decide to write a program to rename all those files, but a problem arises. You cannot do it in any order you like, you have to start with File2 -> File3 in order to avoid conflicts. It’d be nice to just write a function that knows how to change the names of individual files and let another program sort out the rest. This is what aka.rename is about:
>>> from contex import rules
>>> def machine(fn):
return rules(r'File(\d+)', {1: lambda digit: int(digit) + 1}).apply(fn)
>>> aka.rename(machine)
Actions to be taken (simplified; doesn't show the temporary stage):
/home/uglemat/Documents/File0 -> /home/uglemat/Documents/File1
/home/uglemat/Documents/File1 -> /home/uglemat/Documents/File2
/home/uglemat/Documents/File2 -> /home/uglemat/Documents/File3
Target directories:
/home/uglemat/Documents
The files will be renamed as shown above (in two passes though, in order to avoid
collisions). This program searched for name conflicts in all target directories
and did not find any. If errors do pop up, you'll be taken to an emergency mode
where you can roll back changes. Continue? [N/y]: y
Renaming /home/uglemat/Documents/File0 -> /tmp/aka_maok91r8/File0
Renaming /home/uglemat/Documents/File1 -> /tmp/aka_maok91r8/File1
Renaming /home/uglemat/Documents/File2 -> /tmp/aka_maok91r8/File2
Renaming /tmp/aka_maok91r8/File0 -> /home/uglemat/Documents/File1
Renaming /tmp/aka_maok91r8/File1 -> /home/uglemat/Documents/File2
Renaming /tmp/aka_maok91r8/File2 -> /home/uglemat/Documents/File3
True
I used contex.rules to manipulate the string, but you can do whatever you like inside machine, you just need to return the new name of the file.
By default it renames files in the current working directory, but that can be changed with the location argument to aka.rename. aka.copy is basically the same, it just copies files instead. Read the docstrings of those functions to learn the details.
Command line utility
That’s all fine and dandy, but when you just have some files and you need to rename them, you want to do it with a command line utility. This is the basics:
$ aka --help
Useful information ...
$ aka -p 'fn+".jpg"'
That will add a “.jpg” suffix to all files in the working directory. But lets do what we did above with aka.rename:
$ aka -p 'rules(r"File(\d+)", {1: lambda digit: int(digit) + 1})'
The expression after -p doesn’t need to be a new filename, it can also be a unary callable (like machine above) that returns the new filename. That is why the example above works; contex.rules returns a callable.
More complicated renaming schemes
That’s great, but what if it’s not a simple one-liner? Then you need to create a new file, write some python code, launch the python interpreter, import the stuff you need… It’s cumbersome, which is why aka can help with that:
$ aka -e emacs
This will launch emacs and take you to a temporary file which looks kind of like this:
import re
from os.path import join
from contex import rules
# Directories in which to perform changes:
# /home/uglemat/Documents
def rename(fn, dirname):
return fn
Your job is to complete rename, and when you exit the editor it will do the job (after asking you if you want to continue).
Lets do something more advanced, say you have lots of files in ~/Documents/files of the format File<num> and you want to split them into the folders odd and even, like this:
~/Documents/files $ for i in {0..20}; do touch "File$i"; done
~/Documents/files $ ls
File0 File1 File10 File11 File12 File13 File14 File15 File16 File17 File18 File19 File2 File20 File3 File4 File5 File6 File7 File8 File9
~/Documents/files $ mkdir odd even
There is a slight problem in that you can’t rename odd and even, but they are in the same directory. You just got to make sure that the rename function returns a falsy value for those filenames (btw, aka treats directories like files and will rename them too). Lets go to the editor with aka -e 'emacs -nw' and write this:
import re
from os.path import join
from contex import rules
# Directories in which to perform changes:
# /home/uglemat/Documents/files
def rename(fn, dirname):
match = re.search(r'\d+', fn)
if match:
digit = int(match.group(0))
return join('even' if even(digit) else 'odd', fn)
def even(d):
return (d % 2) == 0
The directories odd and even doesn’t match, so rename returns None for those names and thus they are ignored, and the code above works as expected:
~/Documents/files $ aka -e 'emacs -nw'
running $ emacs -nw +9:14 /tmp/aka_3uvuyn8c.py
Aka: Proceed? [Y/n]: y
-- RENAMING FILES IN . --
Actions to be taken (simplified; doesn't show the temporary stage):
/home/uglemat/Documents/files/File3 -> /home/uglemat/Documents/files/odd/File3
/home/uglemat/Documents/files/File18 -> /home/uglemat/Documents/files/even/File18
/home/uglemat/Documents/files/File13 -> /home/uglemat/Documents/files/odd/File13
...
Target directories:
/home/uglemat/Documents/files/odd
/home/uglemat/Documents/files/even
The files will be renamed as shown above (in two passes though, in order to avoid
collisions). This program searched for name conflicts in all target directories
and did not find any. If errors do pop up, you'll be taken to an emergency mode
where you can roll back changes. Continue? [N/y]: y
Renaming /home/uglemat/Documents/files/File3 -> /tmp/aka_st72r5jp/File3
Renaming /home/uglemat/Documents/files/File18 -> /tmp/aka_st72r5jp/File18
Renaming /home/uglemat/Documents/files/File13 -> /tmp/aka_st72r5jp/File13
...
Renaming /tmp/aka_st72r5jp/File3 -> /home/uglemat/Documents/files/odd/File3
Renaming /tmp/aka_st72r5jp/File18 -> /home/uglemat/Documents/files/even/File18
Renaming /tmp/aka_st72r5jp/File13 -> /home/uglemat/Documents/files/odd/File13
~/Documents/files $ ls *
even:
File0 File10 File12 File14 File16 File18 File2 File20 File4 File6 File8
odd:
File1 File11 File13 File15 File17 File19 File3 File5 File7 File9
Installing
aka works only in Python 3.
Install with $ pip3 install aka. You might want to replace pip3 with pip, depending on how your system is configured.
Developing
Aka has some test. Run $ nosetests or $ python3 setup.py test to run the tests. The code is hosted at https://notabug.org/Uglemat/aka
You can install in development mode with $ pip3 install -e ., then your changes to aka will take effect immediately.
License
The library is licensed under the GNU General Public License 3 or later. This README file is public domain.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.