New folders and moving files

Hi, I’m really not liking AppleScript, heh. Coming from a programming background, the pseudo syntax is very annoying and have been unable to find any documentation.

With that said, I am trying to write a script that will loop through all the files in a given folder, make a new folder with each file’s name (excluding the extension), then move the file to the new folder.

Here’s what I got so far:


try
	set myfolder to "External Drive:Blah Blah Blah" as alias
	tell application "Finder"
		repeat with i in myfolder
			make new folder with properties {name:name of i}
		end repeat
	end tell
end try

Of course, it doesn’t work :stuck_out_tongue:

Thanks in advance.

AppleScript: 2.0.1
Browser: Safari 528.16
Operating System: Mac OS X (10.5)

I had many of the same feelings when I first started using AppleScript. After much reading here, on Apple’s AppleScript-users mailing list, and the AppleScript Language Guide, I found two main concepts really helped me become more comfortable with the language. Step zero, if you have not read the ASLG, do that.

The first thing to study (after the ASLG) is the dictionary description of each application’s syntax. This is where the “pseudo-syntax” is defined. It is not really at magical as it looks. Reading the dictionaries is really the only way (after the ASLG) to understand what syntax is available in a particular context. Each entry is either a noun (class) or verb (command). Each application object can have elements and properties. Elements are accessed chiefly through reference forms that use the name of a class (files of folderObj), and properties are accessed through each property’s name (target of finderWindowObj). A twist here is that while application dictionaries are often only usable in an application tell block/statements (and using terms from application . blocks), the entries from the dictionaries of language extensions (OSAX) are available in every context (though using them inside application tell blocks/statements may have unexpected side effects). In Script Editor, choose File > Open Dictionary., sort by Kind and take a look at the “scripting addition” entries. Of particular interest is the Standard Additions extension that implements commands like display dialog, choose folder, [b]POSIX path of[b], read, and write. It used to be that these were not documented in the ASLG and this dictionary was the only place to learn about them.

The second is more technical, but critically important for understanding the little edge cases that come up now and again. This second point is that the way AppleScript works with applications (and even extensions) “under the hood” is through the RPC+query mechanism of AppleEvents. I have lifted the term “RPC+query” from the user “has” that sometimes posts here and the AppleScript-users mailing list. Many of his posts allude to or elucidate this underlying nature of AppleScript. Paying close attention to the contents and structure of the Event Log entries in Script Editor can be a great starting point whenever something unexpected is happening. Sometimes I find it useful to use the AEPrint of command (from List & Record Tools OSAX) to see the AppleEvent structure of various queries and objects.

First problem: The try block is hiding any errors that this might produce. While you might want to silently discard errors after the script is working, it is usually a bad idea to do so while developing a script.

Second problem: repeat with i in myfolder. myfolder is an alias, and has no contents, so repeat will have nothing to do. When put in a Finder block like this, Finder throws an error “Finder got an error: Expected a reference.” (Leopard may be different though). You might use contents of myfolder or items of myfolder here (but see the next item).

Third problem: Because the repeat with i in . operates by indirectly accessing each element of the list argument by index (see ASLG). After enough of the files have been moved out of their original folder, the internal loop index will go out of bounds. The first loop iteration uses item 1 of items of myfolder, the second loop iteration uses item 2 of items of myfolder, etc… If each iteration moves an item out, the total number of items will decrease after each loop iteration. If there are only two items, after the first iteration there will only be one item left, but the loop will try to access item 2 . which will cause an error. A workable way is to extract the items into a list beforehand (or use the get command to explicitly evaluate the items of myfolder reference form).

Here is one way of accomplishing your specified behavior:

--set myfolder to "External Drive:Blah Blah Blah" as alias
set myfolder to choose folder
tell application "Finder" to set theItems to items of myfolder
repeat with i in theItems
	set folderName to trimExtension from name of i -- "name of i" can be done outside a Finder block because "name" is a generic property name (the global "name" and Finder's "name" both use the same internal code: pnam)
	try
		tell application "Finder" to ¬
			set newFolder to make new folder with properties {name:folderName}
		move i to newFolder -- This can be done outside a Finder block, because "move" is a generic command, and i is a reference to a Finder object. This causes the move command to be implicitly sent to Finder.
	on error m
		display dialog "Error while processing "" & name of i & "": " & m with title "Error"
	end try
end repeat

-- A handler to trim off everything after the last dot, if any.
to trimExtension from nameString
	local otid
	set otid to text item delimiters
	try
		set text item delimiters to {"."}
		if (count text items of nameString) is greater than 1 then
			set nameString to text 1 through text item -2 of nameString
		end if
		set text item delimiters to otid
	on error m number n from o partial result r to t
		set text item delimiters to otid
		error m number n from o partial result r to t
	end try
	nameString
end trimExtension

Awesome response.

Regarding the code you wrote for me, it needs an “at my folder”:

set newFolder to make new folder at myfolder with properties {name:folderName}

Now that I have documentation to read, I can correct little things like this and show off some ability. Heheh, I’m learning at least.

Thanks for all the help, Chris.