views:

178

answers:

5

Hi,

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.

A: 

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)
+1  A: 

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.

Steve K
A: 

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.

Jefromi
A: 

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/
nicerobot
A: 

Hi, Trygve. I'm just curious. Why do you want to organize your photos like /YYYY/YY-MM-DD_description/file.jpg instead of /YYYY/MM/DD/file.jpg? I'm curious because I was thinking of doing the opposite myself :-)

Børge