Question about the use of the term "item"

I just completed my first working script. It simply moves all selected files/folders from a Finder window to a folder called “Sundries” in my “Documents” folder, then leaves aliases to those files on the desktop. If a similarly named file/folder is already present in “Sundries”, then the item is renamed successively “original name-1”, “original name-2”, etc, until a unique name is found before moving it.

After much trial and error (three days!!!), I came up with a simple way to refer to a file/folder by its complete path, namely, “item (complete_path & item_name)”. I was especially stumped until I learned that the term “item” was required in the “set name of item …” statement, but was optional or even disallowed in other statements.

I have two questions:

  1. Can you kindly explain why “item” is mandatory in “set name of item …”; optional in “move item …” and “make new alias file at desktop to item …”; and not allowed in “alias [item] …”, despite the fact that the construct is the same in each case, namely “item (complete_path & item_name)”.

  2. Also, I would be very grateful for any comments on how to make the script more elegantly coded, and whether “item (complete_path & item_name)” is a recommended way to refer to a file/folder by its complete path or if there is a better way.

The script is as follows:


tell application "Finder"
	-- "Sundries" is the destination folder of the items to be moved.
	set sundries_path to "MacIntosh HD:Users:username:Documents:Sundries:"
	set input to get selection
	-- Cycle through all the items selected in the Finder window.
	repeat with current_item in input
		set original_path to (container of current_item) as text
		set original_name to name of current_item
		set counter to 0
		set done to false
		set current_name to original_name
		repeat while not done
			try
				-- "alias" command is used as an expedient way to test for the existence of the current item in the "Sundries" folder. If the item doesn't already exist in "Sundries", then execution skips to "on error".
				alias (sundries_path & current_name)
				-- If the current item already exists in the "Sundries" folder, try appending "-1", "-2", and so on until a unique name is found.
				set counter to counter + 1
				set new_name to (original_name & "-" & (counter as string))
				set name of item (original_path & current_name) to new_name
				set current_name to new_name
			on error
				-- Move the uniquely named item to the "Sundries" folder.
				move item (original_path & current_name) to sundries_path
				-- Make an alias of the item on the desktop.
				make new alias file at desktop to item (sundries_path & current_name)
				set done to true
			end try
		end repeat
	end repeat
end tell

bmose:

Here is a thread you might find interesting: http://bbs.applescript.net/viewtopic.php?id=15497

One thing to remember when repeating through filenames like you are is that the items in the list are references, and need to be coerced to be referred to directly. Here is a modified version of your script. I changed only a few things, the main one being taking the setting of the destination folder out of the Finder tell block.

set sundries_path to (path to desktop as Unicode text) & "Sundries:" --This works outside of the Finder tell block

tell application "Finder"
	-- "Sundries" is the destination folder of the items to be moved.
	set input to get selection
	-- Cycle through all the items selected in the Finder window.
	repeat with current_item in input
		--set original_path to (container of current_item) as text --THIS IS NO LONGER NEEDED.
		set original_name to current_item's name--Note apostrophe usage
		set counter to 0
		set done to false
		set current_name to original_name
		repeat while not done
			try
				-- "alias" command is used as an expedient way to test for the existence of the current item in the "Sundries" folder. If the item doesn't already exist in "Sundries", then execution skips to "on error".
				alias (sundries_path & current_name)
				-- If the current item already exists in the "Sundries" folder, try appending "-1", "-2", and so on until a unique name is found.
				set counter to counter + 1
				set new_name to (original_name & "-" & (counter as string))
				set current_item's name to new_name--Note apostrophe usage again
				set current_name to new_name
			on error
				-- Move the uniquely named item to the "Sundries" folder.
				move current_item to sundries_path--Since it is a reference, you can just tell it to move.
				-- Make an alias of the item on the desktop.
				make new alias file at desktop to (sundries_path & current_name)--No need for term [item]
				set done to true
			end try
		end repeat
	end repeat
end tell

Since you are dealing with references to files in your repeat, using the 's for the name property is a neat way to change and obtain the filename.

As you can see, the term ‘item’ is unecessary at any time in your script, again, since you are using references in your loop. That is just as well for me, since I could not answer that question anyway…

I hope this helps somewhat.

Know the difference between an AppleScript string value, an AppleScript file specifier value, and an application object reference.

  1. “MacHD:Users:foo:” is an HFS path string. It has no special meaning in itself; it’s up to your script to interpret it in a meaningful way.

  2. alias “MacHD:Users:foo:” is an alias, a value that identifies a file/folder/disk in your filesystem. It knows a thing or two about filesystems, and can keep track of that file/folder/disk if it’s renamed or (file/folder only) moved to a different location on the same disk.

  3. item “MacHD:Users:foo:” [of app “Finder”] is a reference to an object in the Finder application’s object model, which in turn provides a virtual representation of the filesystem structure (amongst other things). Finder is a program for manipulating the filesystem (one of many available), and as well as a graphical point-n-click user interface it also provides a programmatic user interface, allowing the filesystem to be manipulated using either a mouse or an AppleScript.

Strings and aliases are features of AppleScript. The objects in Finder’s object model and its associated commands are part of the Finder. For your script to talk to Finder, it must do so in terms that Finder understands. Finder doesn’t understand path strings per-se, but it does understand references to its object model, and references are constructed from object specifiers, which in turn are assembled using AppleScript values like integers and strings plus keywords supplied by Finder.

Finder’s pretty flexible in allowing you to construct object model references; for example:

tell app "Finder"

	item "MacHD:Users:foo:"
	
	folder "MacHD:Users:foo:"
	
	folder (alias "MacHD:Users:foo:")
	
	item "foo" of item "Users" of item "MacHD"
	
	folder "foo" of folder "Users" of disk "MacHD"
	
end tell

These are all Finder references, and assuming a folder named “foo” exists in a folder named “Users” on a disk named “MacHD” then Finder will interpret all these references as identifying an object in its object model. You can then send commands to Finder to manipulate that object, and Finder will manipulate the corresponding filesystem contents for you.

Just remember, when you use AppleScript to talk to an application, you talk on the application’s terms. The application defines an interface consisting of commands and (in most cases) an object model, and to control that application successfully, you need to know what that interface looks like and how to use it.

The application’s scripting interface is defined in its dictionary resource, which you can view using Script Editor. One catch: most dictionaries don’t tell you quite everything you need to know to control an application, so you generally need to do a bit of intelligent guesswork, trial-and-error experimentation, reading supplementary documentation (if provided), study of existing scripts, and ask for advice on forums like this to fill in the gaps.

One last comment: AppleScript syntax is a bit annoying as it tries to hide the ‘join’ between things that the language provides and things that the application provides. It’s supposed to help scripters by making everything look simple and consistent, but this can also be counterproductive when users are left wondering why some things work in some places and other things work in other places… but other things don’t work in some places and some things don’t work in other places. So it is good to know there is a distinction, and understand that the stuff on the AppleScript side follows one set of rules, and the stuff on the application side follows another set of rules (with each application having its own variations of those rules too). Some rules are pretty similar, others are rather different. It takes a bit of learning and practice, but once you become adept at identifying who does what and why, it’ll all get a whole lot clearer.

There are various reference guides and books on AppleScript and application scripting, so consider looking into those at some point.

tell application "Finder"
	set sundries_folder to folder "MacIntosh HD:Users:username:Documents:Sundries:"
	repeat with the_item in (get selection)
		set original_folder to container of the_item
		set original_name to name of the_item
		set new_name to original_name
		set counter to 0
		repeat while item new_name of sundries_folder exists
			set counter to counter + 1
			set new_name to original_name & "-" & counter
		end repeat
		set name of the_item to new_name
		move item new_name of original_folder to sundries_folder
		make new alias file to result at desktop
	end repeat
end tell

If you need any bits explained, just ask.

Craig, thank you very much for the helpful suggestions including the use of 's and the revised script.

hhas, I can’t thank you enough for the wonderful discourse on data types, AppleScript vs Application (including Finder), and the fact that AppleScript commands and Finder commands can look similar. I think this similarity is what makes the syntax at times confusing to a novice like myself. But I trust you that the subtle distinctions will become clearer with experience. Due to time constraints, I have only read AppleScript for Absolute Starters thus far but will keep digging deeper.

hhas, I do have one question regarding your script. Since you’ve “set name of the_item to new_name”, why can’t you “move the_item to sundries_folder” but instead have to “move item new_name of original_folder to sundries_folder”?

You have sharp eyes. I avoided going into too much detail on application object references before, as it’s a lot to take in at once, but here goes:

Technically, an application reference doesn’t identify an application object (or objects) itself, but rather it identifies the location in the application’s object model where it expects they’ll be. If an object moves to some other point in the object model, that reference will no longer point to it. Some object specifier forms are better than others at coping with mobile objects, e.g. a by-ID specifier will generally find an object for as long as that object exists as IDs are unique. A by-name specifier will identify the same object as long as the object’s name doesn’t change, but rename that object, or replace it with another of the same name, and that old reference is left identifying nothing, or a different object to before.

In this case, we’re using a by-name reference, so once we change the object’s name, we have to create a fresh reference using the new name; if we try to use the old reference then Finder will raise an ‘object not found’ error. Same thing when you move the object to the desktop folder, though in that case the ‘move’ command helpfully returns a fresh reference to the moved object, so we just use that when creating the alias file to it.

To Master the Apple Event Object Model, one must Move as the Object Model moves. It’s a very Zen thing. And a rather sweet technology, once you wrap your head around it (and have the good fortune of dealing with scriptable applications that are similarly at One with it).

HTH

has

p.s. In fact, there’s a bit more to it than that conceptually, like the fact that ‘application references’ are really first-class query objects (some of the AEOM’s core principles are borrowed from database programming), but I wouldn’t bother getting into that depth of discussion unless you really enjoy geeking out just for the sake of it. :wink:

hhas,
Thank you again helping me climb up the learning curve. From your explanation, I now understand why the alias of a file is so helpful, because it refers to the unique and unchanging file ID no matter where the file is or how it is named/renamed (at least I believe that’s correct!) You have not only an obvious expertise in AppleScript but also a gift for teaching and making things understandable. Forgive me for asking a “final” question: with all the books out there for learning AppleScript, can you kindly recommend the your ONE favorite book that is not only comprehensive but also most well-written for someone like myself who has almost no AppleScript knowledge but who is fairly facile at programming in general? Thanks again.
bmose

Just to be sure we’re clear, AppleScript’s alias values are unrelated to Finder scripting (although Finder does know how to convert alias values to references to its object model, and vice-versa). So yes, AppleScript’s alias values keep track of files and folders based on a unique ID that the Mac’s HFS filesystem assigns to them, but these “IDs” have no relation to the “IDs” I was talking about w.r.t. application object reference forms.

Tricky to say as I’m not familiar with all of them. I think Matt Neuburg’s ‘AppleScript: The Definitive Guide’ is probably the best from the technical angle (a new edition is due very shortly), though first-time programmers may find its businesslike presentation and tone a little intimidating and may prefer the less formal, ‘chattier’ tomes.

I reckon any halfway-decent AppleScript book should get you up and running well enough to knock out more or less functioning code. How clear and accurate an understanding of the AppleScript language and application scripting they’ll give you will vary; there’s an awful lot of confusion, misunderstandings, deeply entrenched myths, etc. about all this stuff. You can often go a long way even on less-than-100%-accurate information, mind you, as long as it’s ‘near enough’ to be useful. e.g. Some books will describe the application object model as ‘object oriented’ in nature, which is misleading as it’s actually a mixture of procedural, OO and relational programming concepts. But it’s still close enough to the truth that you can manage to bash out working code okay, even though you’ll notice some things don’t seem to mesh quite right with the explanation you received.

FWIW, one of the things that helped me most was that once AppleScript got me over my initial ‘Fear of Programming’, I was able to approach some of those scarier-looking ‘real languages’ such as Java, Smalltalk and Python and learn a little bit about those even if I didn’t sit down and use all of them to write real code. I also picked up a high school-level Computing Studies book and read some of that, followed by a copy of ‘Code Complete’ - this taught me a lot about how to plan, design, write and improve code in general, stuff that didn’t seem to get touched on much in AppleScript circles.

That bit of learning really helped me make sense of a lot of things I thought I knew about AppleScript, and drastically simplified and clarified my mental model of the language, how it worked and how to write good-quality code using it. There was a lot less stumbling around in the dark after that! (Mind, it also left me with some fresh misconceptions, such as confusing the application object model for pure OO, but I eventually figured that stuff out after learning some details of how Apple events work.) So if you’ve not programmed before, a bit of background reading like that can be really enlightening once you’ve found your feet.

HTH

has

p.s. If you get really curious about the details, the appscript project on my site adds AppleScript-like application scripting support to Python; might provide an interesting comparison, and there’s some useful documentation and links to be had as well.