Help: Checking server folder for same file

Hello!
I’m piecing together a script that will compare a folder of files to see if that file exists on my server (in a specific folder location). If that file(name) does exist (regardless of it’s file extension) on the server than delete the local file.
Here is what I have so far:


--Server Location
--property rootPathComponents : {"", "Volumes", "graphics", "images"} 
--Desktop Test Location
property rootPathComponents : {"Macintosh HD", "Users", "admin", "Desktop", "graphicsTest", "images"}

set startFolder to (choose folder with prompt "Choose a folder of images you want to move to the server.") as text
tell application "Finder" to set fileList to every file in folder startFolder
--Do the Checking and Deleting
repeat with aFile in fileList
	--Setting the destination path up. 
	set {name:fileName, name extension:fileExtension} to aFile
	--Get name without extension
	set baseName to text 1 thru ((get offset of "." & fileExtension in fileName) - 1) of fileName
	--Set the sub folder names based on file name of aFile
	tell fileName to set {folderA, folderB} to {text 1 thru 2, text 3 thru 4}
	--Set the full path of current file	
	set pathComponents to rootPathComponents & {folderA, folderB}
	if exists text of (pathComponents & baseName as text) then
		try
			do shell script "rm " & quoted form of (startFolder & baseName & ".") & "*"
		end try
	end if
end repeat

the files are named as such: 0000-1006.jpg
So, that’s a file (of 5k) that I have on my local machine.
The same images are stored on the server in a folder structure that is based off of the first 4 digits of the file name.
so for 0000-1006.jpg on the server it should be located here:
graphics/images/00/00/0000-1006.jpg

so the script will hopefully run through my local folder of 5k+ images and remove all that are already existing on the server. Now, the images on the server will likely be in the file format of either tiff, jpg, or png and the images i have on my local are also either tiff, jpg or png.

So, I can’t seem to get it to successfully find the image in my test folder (set up same as server).

Thanks in advance!

Hi.

The difficulty, of course, is in comparing the files’ base names while disregarding their extensions. While the ideal would be to help you complete your own script, I think the necessary text manipulation would be rather fiddly with vanilla AppleScript and using the Finder and multiple shell scripts would lead to slow performances if you had a lot of files to process.

The script below does what I understand to be your aim using ASObjC. Taking the hint from your ‘choose folder’ prompt, it also contains provision for moving the files it doesn’t delete to the subfolder on the server; but that code (near the bottom) is commented out in case you don’t want it. A couple of speed optimisations are possible, but I’ve gone for keeping the code as straightforward (!) as possible. It’s quite fast as it is.


(*
Action:
1. Choose a folder containing image files.
2. Using the first four characters of each file name, work out the path to a corresponding subfolder on a server.
3. Check the subfolder for items having the same base name, though not necessarily the same extension, as the file in the chosen folder.
4. If such an item exists in the subfolder, delete the file in the chosen folder.
4a. Otherwise (commented out) move the file to the subfolder as implied by the 'choose folder' prompt.

Assumptions:
1. All the files in the chosen folder are named using the scheme: "nnnn-nnnn.extn"
2. The relevant subfolders on the server already exist.
*)
use AppleScript version "2.4" -- Mac OS 10.10 (Yosemite) or later.
use framework "Foundation"
use scripting additions

--Server Location
--property rootPath : "/Volumes/graphics/images"
--Desktop Test Location
property rootPath : "/Users/admin/Desktop/graphicsTest/images"

set startFolder to (choose folder with prompt "Choose a folder of images you want to move to the server.")
processFolder(startFolder)

on processFolder(startFolder)
	set |⌘| to current application
	-- Get an NSURL to the chosen folder.
	set startFolderURL to |⌘|'s class "NSURL"'s fileURLWithPath:(POSIX path of startFolder)
	-- Get the folder's visible contents, noting whether or not they're regular files (as opposed to alias files, links, directories, or bundles).
	set fileManager to |⌘|'s class "NSFileManager"'s new()
	set startFolderContents to fileManager's contentsOfDirectoryAtURL:(startFolderURL) includingPropertiesForKeys:({|⌘|'s NSURLIsRegularFileKey}) options:(|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	-- Get the contents' names without the extensions.
	set baseNames to (startFolderContents's valueForKey:("lastPathComponent"))'s valueForKey:("stringByDeletingPathExtension")
	
	-- Get the path to the root folder on the server as an NSString.
	set rootPath to |⌘|'s class "NSString"'s stringWithString:(rootPath)
	-- Repeat with each item in the chosen folder.
	repeat with i from 1 to startFolderContents's |count|()
		set thisItem to item i of startFolderContents
		-- Act if this item's a regular file.
		if ((thisItem's getResourceValue:(reference) forKey:(|⌘|'s NSURLIsRegularFileKey) |error|:(missing value))'s end as boolean) then
			-- Get the item's base name.
			set thisBaseName to item i of baseNames
			-- Derive a path subsequence ("nn/nn") from the first four characters.
			set subfolderSequence to (thisBaseName's stringByReplacingOccurrencesOfString:("^([0-9]{2})([0-9]{2}).++$") withString:("$1/$2") options:(|⌘|'s NSRegularExpressionSearch) range:({0, thisBaseName's |length|()}))
			-- Append this to the root folder path.
			set pathToServerSubfolder to (rootPath's stringByAppendingPathComponent:(subfolderSequence))
			-- Get the names, without extensions, of the items in the indicated subfolder.
			set baseNamesInServerSubfolder to ((fileManager's contentsOfDirectoryAtPath:(pathToServerSubfolder) |error|:(missing value))'s valueForKey:("stringByDeletingPathExtension"))
			-- If any of these names match the base name of the current item, delete the item from the chosen folder.
			if ((baseNamesInServerSubfolder's containsObject:(thisBaseName)) as boolean) then
				tell fileManager to removeItemAtURL:(thisItem) |error|:(missing value)
			else
				-- Otherwise (if the code below's uncommented) move the item, with its current name, to the subfolder on the server.
				(* set destinationPath to (pathToServerSubfolder's stringByAppendingPathComponent:(thisItem's lastPathComponent()))
				set destinationURL to (|⌘|'s class "NSURL"'s fileURLWithPath:(destinationPath))
				tell fileManager to moveItemAtURL:(thisItem) toURL:(destinationURL) |error|:(missing value) *)
			end if
		end if
	end repeat
end processFolder

Awesome! Thanks Nigel.
Your assumption #2 is incorrect. I’m unsure if the folder exists for every image. If it doesn’t exist, then it can just skip and go onto the next.

OK. That means each subfolder’s existence needs to be checked each time to avoid run-time errors. This makes it worth implementing one of the optimisations I didn’t use before: getting the root folder’s entire contents once before the repeat instead of getting each relevant subfolder’s contents once for each file. There are in fact a couple of built-in methods for returning subpaths from the root folder, so if you’re not considering moving the items which aren’t deleted, full paths aren’t needed.


(*
Action:
1. Choose a folder containing files whose base names all consist of two groups of four digits separated by a dash.
2. Derive a subpath from each file's base name, such that "aabb-nnnn.extn" becomes "aa/bb/aabb-nnnn".
3. If the result matches a similar subpath for an existing item in a hierarchy on a server, delete the file in the chosen folder.
3a. Otherwise (* commented-out code *) move the file to the hierarchy subfolder implied by the subpath, creating the subfolder (or subfolder chain) first, if necessary.
*)
use AppleScript version "2.4" -- Mac OS 10.10 (Yosemite) or later.
use framework "Foundation"
use scripting additions

--Server Location
--property rootPath : "/Volumes/graphics/images"
--Desktop Test Location
property rootPath : "/Users/admin/Desktop/graphicsTest/images"

set startFolder to (choose folder with prompt "Choose a folder of images you want to move to the server.")
processFolder(startFolder)

on processFolder(startFolder)
	set |⌘| to current application
	-- Get NSURLs for the chosen folder and for the root folder of the hierarchy on the server.
	set startFolderURL to |⌘|'s class "NSURL"'s fileURLWithPath:(POSIX path of startFolder)
	(* set rootURL to |⌘|'s class "NSURL"'s fileURLWithPath:(rootPath) *)
	-- Get the chosen folder's visible contents, noting whether or not they're regular files (as opposed to alias files, links, directories, or bundles).
	set fileManager to |⌘|'s class "NSFileManager"'s new()
	set startFolderContents to fileManager's contentsOfDirectoryAtURL:(startFolderURL) includingPropertiesForKeys:({|⌘|'s NSURLIsRegularFileKey}) options:(|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	-- Get the contents' names without the extensions.
	set baseNames to (startFolderContents's valueForKey:("lastPathComponent"))'s valueForKey:("stringByDeletingPathExtension")
	-- Get subpaths to every item in the destination hierarchy, also without name extensions. The array may be added to below.
	set serverBaseNameSubpaths to ((fileManager's subpathsAtPath:(rootPath))'s valueForKey:("stringByDeletingPathExtension"))'s mutableCopy()
	
	-- Repeat with each item in the chosen folder.
	repeat with i from 1 to startFolderContents's |count|()
		set thisItem to item i of startFolderContents
		-- If the item's a regular file ..
		if ((thisItem's getResourceValue:(reference) forKey:(|⌘|'s NSURLIsRegularFileKey) |error|:(missing value))'s end as boolean) then
			-- Work out a corresponding destination hierarchy subpath for the item, leaving off the name extension.
			set destinationFileSubpath to ((item i of baseNames)'s stringByReplacingOccurrencesOfString:("([0-9]{2})([0-9]{2})") withString:("$1/$2/$1$2") options:(|⌘|'s NSRegularExpressionSearch) range:({0, 4}))
			if ((serverBaseNameSubpaths's containsObject:(destinationFileSubpath)) as boolean) then
				-- If the result's already in the array of destination hierarchy subpaths, delete the item in the chosen folder.
				tell fileManager to removeItemAtURL:(thisItem) |error|:(missing value)
			else
				(* -- Otherwise get the subfolder-chain component of the subpath.
				set destinationSubfolderSubpath to (destinationFileSubpath's substringToIndex:(5))
				-- Make a URL for the subfolder it represents.
				set destinationSubfolderURL to (rootURL's URLByAppendingPathComponent:(destinationSubfolderSubpath))
				-- If the subpath's not in the hierarchy subpath array, the subfolder doesn't exist. Create it (and the containing folder, if necessary) and add the subpath to the array.
				if (not ((serverBaseNameSubpaths's containsObject:(destinationSubfolderSubpath)) as boolean)) then
					tell fileManager to createDirectoryAtURL:(destinationSubfolderURL) withIntermediateDirectories:(true) attributes:(missing value) |error|:(missing value)
					tell serverBaseNameSubpaths to addObject:(destinationSubfolderSubpath)
				end if
				-- Move the current item, with its current name, from the chosen folder to the relevant destination subfolder.
				set destinationFileURL to (destinationSubfolderURL's URLByAppendingPathComponent:(thisItem's lastPathComponent()))
				tell fileManager to moveItemAtURL:(thisItem) toURL:(destinationFileURL) |error|:(missing value)
				-- Add its base-name subpath to the subpath array.
				tell serverBaseNameSubpaths to addObject:(destinationFileSubpath) *)
			end if
		end if
	end repeat
end processFolder

Edit: Added commented-out code for moving the files which aren’t deleted into the server hierarchy, as in post #2. The code creates any necessary subfolders which don’t already exist.

NG,
You da Man! This is a huge help, thanks!