Moving a file into a subdirectory, based on a partial string match?

Hey all, I’ve found myself working with applescript for about a month now. I’m working on a solution, but I can’t seem to break through.

The solution will move a file, from a source directory, to a subfolder of a destination directory. The file and subfolder have partially matching names.

So, 3 important items:

-A file, with a naming format like this: “TV1001_JPartial_String_Match_Here_FILE_34059345.pdf”

-A source directory. The name of this is not relevant, as I’ll just declare this folder, and not do anything else with it.

-A destination subdirectory, with a naming format like this:
“55555_JPartial_String_Match_Here_FOLDER_390489348”. The file will be placed in the matching subdirectory.

So, moving into a specific directory, if there is a partial match. I’ve gotten a decent part of the way. Here is my current script.

property delim : "_"

set myStrings to ¬
	"TV1001_JPartial_String_Match_Here_FILE_34059345"

set strLength to count of characters of myStrings
set {TID, AppleScript's text item delimiters} to ¬
	{AppleScript's text item delimiters, delim}


set sTrim1 to text 9 thru (strLength + (offset of "J" in text)) of myStrings

set newStringsList to {}
repeat with thisString in paragraphs of sTrim1
	set delimCount to (length of text items of thisString) - 1
	if delimCount ≥ 3 then
		set thisString to text items 1 thru 4 of thisString
		set thisString to thisString as string
		copy thisString to end of newStringsList
	end if
end repeat

set AppleScript's text item delimiters to linefeed & linefeed
set myNewStrings to newStringsList as text
set AppleScript's text item delimiters to TID


set sourceDir to "~/Desktop/sourceDir"
set destDir to "~/Desktop/DestDir"
set subString to myNewStrings

do shell script "/usr/bin/find " & sourceDir & " -depth 1 -type d  -name '*" & subString & "*' -exec mv {} " & destDir & " \\; "

display dialog myNewStrings

As you can see, I’m using a shell script to do the moving part, and finding the potential match before that.

Any ideas?

You don’t state what your actual issue is but three things come to mind.

First, if you are processing a single file, why have a repeat loop for the ‘paragraphs’? There will only be a single paragraph (unless you have impossibly weird filenames, which doesn’t seem to be the case). And why have paragraphs at all? Just work directly with the text.

For example…

set sTrim1 to "Partial_String_Match_Here_FILE_34059345" -- starting point based on prior code
set AppleScript's text item delimiters to "_"
set delimCount to (count of text items of (sTrim1 as text))
if delimCount is greater than 4 then
	set subString to text items 1 thru 4 of sTrim1
	subString as text
end if
--> Partial_String_Match_Here

You can further reduce the above code but it should be more clear this way.

Second, while the shell works with ‘~’, applescript struggles with it (and often fails). So use something like this which will give you the posix path for the shell as well as make it easy to coerce into an alias:

[format]set destDir to POSIX path of ((path to desktop as text) & “destDir:”)
→ /Users/username/Desktop/destDir/
set destDira to POSIX file destDir as alias
→ alias “MacHD:Users:username:Desktop:destDir:”[/format]

FYI,there are other predetermined path locations (e.g. path to home folder). Now you can get your destination subdirectory with something like this:

set destDir to POSIX path of ((path to desktop as text) & "destDir:")
set destDira to POSIX file destDir as alias
tell application "Finder"
        set destDirSubdirs to (every folder of destDira whose name contains "Partial_String_Match_Here")
    set subDir to    POSIX path of (item 1 of destDirSubdirs as alias)
end tell
--> /Users/username/Desktop/destDir/55555_JPartial_String_Match_Here_FOLDER_390489348/

Third, I’m not sure about the specific intent of the shell script. Is it to find the file to move or its destination subdirectory? If it is the latter, then you need to replace ‘sourceDir’ with ‘DestDir’ (as well as some other changes).

If it’s the file to move, then why? You already have the file.
[format]~/Desktop/sourceDir/TV1001_JPartial_String_Match_Here_FILE_34059345.pdf[/format]

You can just move it using applescript, like so:

set destDir to POSIX path of ((path to desktop as text) & "destDir:")
--> /Users/username/Desktop/destDir/
set destDira to POSIX file destDir as alias
--> alias "MacHD:Users:username:Desktop:destDir:"
set sourceDir to POSIX path of ((path to desktop as text) & "sourceDir:")
--> /Users/username/Desktop/sourceDir/
set sourceDira to POSIX file sourceDir as alias
--> alias "MacHD:Users:username:Desktop:sourceDir:"
set myStrings to "TV1001_JPartial_String_Match_Here_FILE_34059345"

set mPDF to (sourceDira & myStrings & ".pdf" as text) as alias

tell application "Finder"
	set destDirSubdir to (every folder of destDira whose name contains "Partial_String_Match_Here")
	set subDir to item 1 of destDirSubdir
	POSIX path of (subDir as alias)
	
	move mPDF to subDir
end tell

The above also gives you everything you need to build posix file references in case you want to use ‘mv’ in the shell.

Finally, if you want to use find/exec/mv for other reasons, your find command uses ‘-type d’ which restricts the results to directories, so you won’t find your pdf.

When I use the following in the terminal, it moves matching files to ~/Desktop/DestDir, but not to the subdirectory.
[format]/usr/bin/find ~/Desktop/sourceDir -depth 1 -name ‘Partial_String_Match_Here’ -exec mv {} ~/Desktop/destDir ;[/format]

Putting the applescript component aside for a moment, what terminal command will achieve your purposes? I find it easier to construct a ‘do shell script’ when the terminal command is known.

Hello, and welcome to forum. Most newbies aren’t necessarily served by jumping straight into shell scripts. You may be able to use the Finder with a small file/folder quantity.

set fileList to {"TV1001_JPartial_String_Match_Here_FILE_34059345.pdf"} --assumedly more than one
set p2D to (path to desktop as text)
set {sourceFolder, destFolder} to {p2D & "sourceDir", p2D & "DestDir"}
tell application "Finder" to repeat with aFile in fileList
	move aFile to folder destFolder's folder 1 whose its name contains (aFile's (text ((my (offset of "_J" in aFile)) + 2) thru ((my (offset of "_FILE" in aFile)) - 1)))
end repeat

Thank you, Mark and Mockman. I was able to put together something I believe to be close to the result. Coming from OO-programming, I was having a hard time debugging.

Excuse the comments, I’m trying to get an overview of my script:

tell application "Finder"
	
	set selected to selection --Select source folder
	set current_folder to item 1 of selected --first item
	set mlist to every file of current_folder --folder as list
	set destDir to POSIX path of ((path to desktop as text) & "destDir:")
	--> /Users/username/Desktop/destDir/
	set destDira to POSIX file destDir as alias
	
	
	repeat with this_file in mlist --for each
		set cur_ext to name extension of this_file
		set strLength to count of characters of this_file
		set new_name to text 9 thru (strLength + (offset of "J" in text) - (length of cur_ext) + 2) of (name of this_file as text) --this is trimming
		
		set AppleScript's text item delimiters to "_"
		set delimCount to (count of text items of (new_name as text))
		if delimCount is greater than 4 then
			set subString to text items 1 thru 4 of new_name
			subString as text
		end if --Trim down to 3 underscores
		
		set myList to subString
		set saveTID to AppleScript's text item delimiters
		set FinalString to myList as text
		set AppleScript's text item delimiters to saveTID
		display dialog FinalString --Convert from list to string
		
		
		
		--Move file if folder contains trimmed string
		set destDirSubDir to (every folder of destDira whose name contains FinalString)
		
		if (name of destDirSubDir contains FinalString) then
			move this_file to destDirSubDir
		end if
		
	end repeat
end tell

It seems the script is 4 parts.
-1. Set up some files and folders, that I’ll use later.
-2. Trim the string, remove up to the 3rd underscore. The string is now a list.
-3. Put the list into a string again.
-4. Move the file into a subdirectory, if new string is contained in name of any folders.

However, I get an error of error “Can’t get name of {}.” number -1728 from name of {}, highlighting FinalString in the last if.

This seems like it tries to get the name of an empty array.

Some major things…

strLength is trying to count a file object, and returns ‘0’. Instead, use ‘set strLength to count of (get name of this_file)’ which returns ‘51’.

Your ‘set new_name’ math confuses me. It is evaluating to…

Can you provide what ‘new_name’ should be after this? I’m guessing that you can just leave out either the ‘text 9’ or the offset. So ‘set new_name to text 9 thru ((length of (get name of this_file)) - (length of cur_ext) - 1) of (get name of this_file)’ captures ‘Partial_String_Match_Here_FILE_34059345’ or text 9 thru 47.

Alternatively, you can specify the last character of a string (character 51 or ‘f’) with ‘-1’. The ‘5’ next to the extension (character 47) is -5. So ‘text 9 thru -5’ would capture ‘Partial_String_Match_Here_FILE_34059345’.

Repeat loop… if you’re only going to have a single file selected, then you don’t need to use repeat. Just use… ‘set this_file to item 1 of mlist’. But if you want the script to move multiple files, then you need to make other changes.

Finally, the empty list error you refer to results from asking the ‘name of destDirSubDir’, instead of asking the folder’s name. Instead, ask ‘if name of (item 1 of destDirSubDir)’ contains that string. Then, ‘move this_file to item 1 of destDirSubDir’.

tell application "Finder"
	
	set selected to selection --Select source folder
	set current_folder to item 1 of selected --first item
	set mlist to every file of current_folder --folder as list
	-- set destDir to POSIX path of ((path to desktop as text) & "destDir:")
	-- tell me to set destDira to POSIX file destDir as alias
	set destDira to ((path to desktop) as text) & "destDir:" as alias
        --> alias "MacHD:Users:username:Desktop:destDir:"

	repeat with this_file in mlist --for each
		set cur_ext to name extension of this_file
		set strLength to length of (get name of this_file)
		set new_name to text 9 thru ((length of (get name of this_file)) - (length of cur_ext) - 1) of (get name of this_file)
		--> Partial_String_Match_Here_FILE_34059345
	end repeat
	
	set AppleScript's text item delimiters to "_"
	set delimCount to (count of text items of new_name)
	if delimCount is greater than 4 then
		set subString to text items 1 thru 4 of new_name
	end if --Trim down to 3 underscores
	
	set FinalString to subString as text
	display dialog FinalString --Convert from list to string
	-- Partial_String_Match_Here
	
	--Move file if folder contains trimmed string
	set destDirSubDir to (every folder of destDira whose name contains FinalString)
	
	if name of (item 1 of destDirSubDir) contains FinalString then
		move this_file to item 1 of destDirSubDir
	end if
end tell

And a few comments…

In general, you can get the count (or its synonym ‘length’) of ‘text’ or ‘characters’. As the file name is text, you can forego getting its characters to determine strLength.

‘name of’ returns text so ‘as text’ is redundant in ‘name of this_file as text’

saveTID: It doesn’t harm this script but the ‘set saveTID’ should be set at the beginning of the script (or anywhere before you first set them to ‘_’).

You can do without ‘mylist’. Optionally, you can do without ‘FinalString’ as well (e.g. ‘set subString to subString as text’).

Posix file: If you use it straight up inside an application tell block it generates a silent error. Preface it with ‘tell me to’ or move it outside the tell block.

And actually, if you don’t have a specific need for posix (i.e. for use in the shell) then you can skip that step:
[format] – set destDir to POSIX path of ((path to desktop as text) & “destDir:”)
– tell me to set destDira to POSIX file destDir as alias
set destDira to ((path to desktop) as text) & “destDir:” as alias[/format]