Through the last years I have different types of software to organize my photo and music collections. This has resulted in differences in directory structure, and I'd like this to be uniform.
Problem a: Music collection
I want my music collection to look like: /Artist/Album/files.*
but now there are several instances of /A/Artist/Album/files.*
I'm trying to write a script which:
1. Find all folders with 1 character,
2. Move contents of each one-character folder, to /Artist/
(Flatten structure, and handle spaces in filenames)
find ./Artists/ -name "?" -maxdepth 1 -mindepth 1 | mv * ./Artists/
Gets me halfway, but it doesn't handle spaces in directory names, and I'm a bit unsure if it has other pitfalls.
Problem b: Photo collection
I have a very similar situation here, most of my collection looks like I want it.
Desired:
/Photos/2009/2009-08-07 description/filename.jpg
Current situation:
/Photos/2009/03/21/filename.jpg
I need a script which:
1. Find all folders which match /yyyy/mm/dd/
2. Move content to /yyyy-mm-dd/
3. Delete old folders
Background
I believe a bash script would be well suited, but I am also up and ready for something in python.
I'm using Ubuntu 9.04.
Thank you in advance.
For your second request, try something like this:
#!/bin/bash
find $PHOTO_DIR -regextype posix-extended -type d -regex '.*/[0-9]{4}/[0-9]{2}/[0-9]{2}$' |
while read dir; do
newdir="$(echo $dir | sed 's@/\([0-9]\{4\}\)/\([0-9]\{2\}\)/\([0-9]\{2\}\)$@/\1-\2-\3@')"
mv "$dir" "$newdir"
rmdir "$(dirname $dir)"
rmdir "$(dirname $(dirname $dir))"
done
This worked fine for my simple test case; to make sure it works right for you, put an echo
in front of the three action lines (mv
and twice rmdir
).
As a bit of general advice, piping find's output into a while read
loop isn't just for scripts - it's a very powerful one-liner technique for going beyond find
's -exec
capability.
Try this.
find ./Artists/ -name "?" -maxdepth 1 -mindepth 1 -exec mv {} ./Artists/ \;
Passing the output of find loses the distinction between spaces in file names and separate files. -exec will execute mv on each found file, one at a time. -ok does the same thing but asks you for confirmation first.
I have a simple Python script. Although your case is very specific, I prefer dispatching photos to separate folders by looking their EXIF information. It copies photos from SRC to DST where it creates a folder for each day. It uses EXIF.py. So here it goes:
import EXIF, os, re, shutil, sys
__date__ ="$Jun 4, 2009 1:27:16 PM$"
if __name__ == "__main__":
if len(sys.argv) < 3:
print "No params given. PhotoDispatcher.py <SRC> <DST>"
exit(1)
src = sys.argv[1]
dst = sys.argv[2]
for path, directories, files in os.walk(src):
for filename in files:
curfile = src+'/'+filename
f = open(curfile, 'rb');
tags = EXIF.process_file(f, stop_tag='EXIF DateTimeOriginal')
f.close()
try: dateTimeOrig = tags['EXIF DateTimeOriginal'].__str__()[0:10]
except KeyError:
print "unable to read DateTimeOriginal tag", filename
continue
dirName = re.sub(':','.', dateTimeOrig)
newdir = dst+'/'+dirName
try: os.mkdir(newdir)
except os.error:
print "unable to create directory: ", os.error
newfile = newdir+'/'+filename
print curfile, '-->', newfile
shutil.move(curfile, newfile)
Use find's -print0 and xargs' -0 to handle spaces.
Try something like:
find [A-Z]/* -type d -maxdepth 1 -mindepth 1 -print0 \
| xargs -r0 -I'{}' mv {} Artists/