Recursively rename files and folders

Hi,
A friend of mine has a Buffalo Terastation NAS and needs to store a directory structure on it. The problem is that the device does not support long names, so he’s looking at having to bulk rename multiple items. I can script bulk renaming of files, that’s fairly simple, however, when folders become involved is where I get a little stuck as I need to potentially rename a folder with a long name, which would then screw up the recursvice search as the folder I’m looking for won’t exist.

Does anyone have an existing script that will recurse through a dropped folder renaming any files and folders it finds whose name is over a specific number of characters to another specific length?

I think there are more problems here than you think. Consider:

  1. If you simply truncate the names according to a simple scheme, that scheme will have to include a check that the truncated name does not already exist in the target folder as a result of a previous truncation.

  2. You have to rename and move as you go along unless your friend’s machine can hold duplicates of all the files he wants to move, or he intends to rename all of his own files and folders before backing them up to the NAS.

  3. See this Code Exchange hint for the rapid production of a directory structure. See the Finder’s “entire contents” for getting all the files and folders.

This is from this bbs, and I apologize to it’s author - I didn’t make a note.

to drill_down(a_folder)
	tell application "Finder"
		set file_list to files of a_folder
		set folder_list to folders of a_folder
	end tell
	repeat with I in file_list
		processDrilledDownFile(I)
		-- relieve the script by handling the found files first, 
		-- before diving deeper into the recursion with the found folders,
		-- as this will minimize occurences of a stack overflow 
	end repeat
	repeat with I in folder_list
		processDrilledDownFolder(I)
		drill_down(I) -- diving into the recursion with the found folders here
	end repeat
end drill_down

-- similar handler for Folders, or integrate the two
on processDrilledDownFile(a_file)
	-- a_file is passed on to the processDrilledDownFile handler as a Finder file object
	-- so it must be further processed starting from within a "tell application Finder" block
	tell application "Finder"
		-- do your file processing here
	end tell
end processDrilledDownFile

drill_down(choose folder)

I haven’t been doing a lot of scripting lately and have lost it like any other unused language

i too am trying to develop a script that can simply truncate files over 31 chars yet include the extension info

for movement to a windblows server

TIA for any help

Hi Joe.

This could be prettier, but it’s a start. It doesn’t remove illegal characters, but does handle varying numbers of characters in extensions.


set theFile to (choose file without invisibles)
set fileName to name of (info for theFile)
set theExt to name extension of (info for theFile)
set nameLength to count of fileName
set extLength to count of theExt
set cutOff to (30 - extLength)--30 to account for the "."
if nameLength > 31 then set shortName to text 1 through cutOff of fileName & "." & theExt

j

Hi.

The Finder itself apparently works recursively when getting the entire contents of a folder. Folders always appear in the returned list before any items they may contain. So working backwards through the list will only rename folders whose items have already been processed and no harm will be done to the process.

Here’s a script you can adapt to your own needs. It duplicates a user-chosen folder to the desktop and returns a list containing the paths to the (duplicate) folder and all the items in its hierarchy. It then works textually through the paths, looking for names with more than 31 characters. Any such names are truncated and the items to which they belong are renamed.

The renaming scheme here uses the first 15 characters of the name and the last 15 (including any extension) and joins them with an ellipsis character. I reckon that should reduce the risk of name clashes; but if there are any, the last two characters of the new base name of the current item are replaced with a two-digit number, which is incremented until no clash occurs.

on main()
	set astid to AppleScript's text item delimiters
	
	truncateNames(getPaths())
	
	set AppleScript's text item delimiters to astid
	showMessage("Done!", note)
end main

(* Duplicate a chosen folder to the desktop and get the paths to it and everything in it. *)
on getPaths()
	set originalFolder to (choose folder)
	
	tell application "Finder"
		try
			set dupFolder to (duplicate originalFolder to desktop)
		on error msg number -15267
			my showMessage("A folder with the same name already exists on the desktop.", stop)
			error number -128
		end try
		
		set AppleScript's text item delimiters to return
		set thePaths to paragraphs of ((entire contents of dupFolder) as Unicode text)
		set beginning of thePaths to dupFolder as Unicode text
	end tell
	
	return thePaths
end getPaths

(* Get item names from a list of paths, truncate any that have more
than 31 characters, and rename the items to which they refer. *)
on truncateNames(thePaths)
	set colon to ":" as Unicode text
	set ellipsis to "." as Unicode text
	set dot to "." as Unicode text
	set AppleScript's text item delimiters to colon
	
	considering case
		repeat with i from (count thePaths) to 1 by -1
			set thisPath to item i of thePaths
			if ((count thisPath) > 0) then -- There's sometimes a blank item at the end of the list.
				set thisname to text item -1 of thisPath
				if ((count thisname) is 0) then set thisname to text item -2 of thisPath -- Folder or package path ending in ":".
				if ((count thisname) > 31) then
					set newName to text 1 thru 15 of thisname & ellipsis & text -15 thru -1 of thisname
					set counter to 100
					repeat -- until no name clashes to cause errors.
						try
							tell application "Finder" to set name of item thisPath to newName
							exit repeat
						on error
							-- Make a new name with a two-digit number after the base name.
							set counter to counter + 1
							set numberInsert to text 2 thru 3 of (counter as Unicode text)
							if (newName contains dot) then -- Names with extensions.
								set AppleScript's text item delimiters to dot
								set extnLen to (count text item -1 of newName) + 1
								set newName to text 1 thru (29 - extnLen) of thisname & numberInsert & text -extnLen thru -1 of newName
								set AppleScript's text item delimiters to colon
							else -- Names without extensions.
								set newName to text 1 thru 29 of newName & numberInsert
							end if
						end try
					end repeat
				end if
			end if
		end repeat
	end considering
end truncateNames

on showMessage(msg, iconType)
	beep
	tell application (path to frontmost application as Unicode text)
		display dialog msg buttons {"OK"} default button 1 with icon iconType
	end tell
end showMessage

main()

Hi

I’ve just spent 2 weeks on the same problem… long names and long characters are not supported… I suspect that if your friend is trying to connect to the drive via afp:// he will have a limit of 30 characters… if he uses smb:// the character limit will be 255 and he should be fine…

Furthermore if he connects via ftp:// as admin with the program ‘Transmit’ to the folder he wishes to drop the data into… there is no restriction on illegal characters… I assume the same would be true of filename length. He would need to enable ftp sharing for the shared volume on the Terastation and then allow the relevant user or the admin account in the ‘Group Management’ to be allowed to access the shared volume because ftp doesn’t recognise group authentication only user level.

Hope this is not too late and saves some time.

Thanks,

Dominic.