Renaming files in a directory tree

From IlugCal

This script may be used to rename files in a directory tree, by replacing white-spaces with hyphen and changing all uppercase characters to lowercase. It would generate a simple log file of the changes it has made, and also warns the user before accidental replacing of the files.

Usage: 1. Copy the code below, and save it in a file an name it renamer.py 2. Open a terminal and type in python renamer.py /nameOfDirectory, where nameOfDirectory can be an absolute path or a directory under your current working directory.

#!/usr/bin/python

import sys, os, re, time 

def gettime():
	timestamp = time.localtime(time.time())
	return time.asctime(timestamp)
	
def listdir(dirPath):
	fileshere = os.listdir(dirPath)
	for name in fileshere:
		path_old = os.path.join(dirPath, name)
		name_low = name.lower()
		name_low_hyp = name_low.replace(" ","-")
		if name_low_hyp in fileshere and name_low_hyp!= name:
			print name_low_hyp + " already exists. Replace it? "
			ans = raw_input(" Remove existing file?[y|n] ")
			if ans == 'n':
				name_low_hyp = '~' + name_low_hyp
		path_new = os.path.join(dirPath, name_low_hyp)
		os.rename(path_old, path_new)
		f.write(gettime() + "\t "+ name + "  ---->  " + name_low_hyp + "\n")
		if os.path.isdir(path_new):
			listdir(path_new) 

f = open(r'remover.log', 'w')
f.write('****************** renamer.py log file ******************\n')
f.write('renamer.py started at ' + gettime() + '\n')

for name in sys.argv[1:]: listdir(name)
	
f.write('remover.py ended at ' + gettime())

Feel free to tune it for your needs.

Sayamindu Dasgupta's version, ... a bit edited

#!/usr/bin/env python
import os, sys, shutil

def move_stuff(root, name):
   newname = name.lower()
   if newname.count(" ") > 0:
       newname = newname.replace(" ", "")
   print "Renaming " + os.path.join(root, name) + " to " + os.path.join(root, newname)
   shutil.move(os.path.join(root, name), os.path.join(root, newname))



if len(sys.argv) < 2:
   print "Usage:\n" + sys.argv[0] + " directory"
   raise SystemExit

top=sys.argv[1]
for root, dirs, files in os.walk(top, topdown=False):
   for name in files:
       move_stuff(root, name)
   for name in dirs:
       move_stuff(root, name)

print "Done!!"


[edit] bash approach

Reply to http://list.ilug-cal.org/pipermail/ilug-cal-discuss/2007-August/001589.html


#!/bin/bash

# Better unset the variables first to avoid any problems

unset i filename list

# Read in the list of files recursively into an array
# Note that by changing the arguments to find, you can generate the kind of list you want

while read -d $'\0' filename
do
    list[i++]="$filename"
done < <(find "$1" -print0)

# Actual processing
# We loop over the array in reverse because otherwise, renaming would mismatch the list in the array
# We will not rename the directory given as the argument

for (( i=$(( ${#list[@]} - 1 )) ; i > 0 ; i-- ))
do
    # The following one liner actually does all the work
    mv -v "${list[i]}" "${list[i]%/*}/$( echo "${list[i]##*/}" | tr ' [:upper:]' '-[:lower:]' )" 2>/dev/null
done

Invoke the script with the name of the parent directory as the argument. Make sure you quote the name/path if there are spaces or newlines. The script will NOT rename the directory provided as the argument.

There is a caveat in this particular `tr' approach that there will be an error if the filename is passed through without translation. Since this is mv, it can be safely ignored. With the stderr redirected, you won't even notice any errors. This'll need to be refined for useage with any other problem.

Anyway, this should server as a skeleton for recursive directory processing in bash. The while loop is important because it allows us to read in a directory structure with spaces and newlines in the filenames. Aftwards, there are loads of possibilities by looping through the array containing the list of files.

HTH.

Mrugesh

P.S. Btw, there are loads of possibilities for improving this script. One could tighten it up for signal handling or error processing etc. That applies for most of the bash scripts though, I guess.

Personal tools