detecting USB disk mount...

I’ve been cruising around trying to find script code to do the following:

  1. detect my USB thumb drive mounting
  2. copy all contents into a folder
  3. delete the files from the drive
  4. eject the drive
  5. beep

I can handle the last four steps, but how do I detect the appearance of my thumb drive?

Any ideas?

Thanks,
Marc

Sure wish somebody had replied to this. :wink: I’m trying to do the very same thing today. I was hoping not to reinvent the wheel. I’m experimenting with folder actions on the /volumes folder, but having inconsistent results…

Model: iBook G4
AppleScript: 1.10.3
Browser: Safari 417.8
Operating System: Mac OS X (10.4)

tell application "Finder" to set D to count of disks
D --> number of partitions you have + 1 for Network + 1 if Stick present

or, if you know the name of the stick,

tell application "Finder" to if ("MY-STICK") is in (name of disks) then display dialog "Bingo"

In either case, if you want to detect the stick without having to start the script, then you have to save your script as a stay-open application with an idle handler in it that checks for the stick every so often.

As an afterthought, I think I have read that an idle handler is more reliable than a Folder Action on /Volumes. Your mileage may vary.

There is an elegant way to do this.

Make your script that will serve as a Folder Action:

on adding folder items to this_folder after receiving these_items
	tell application "Finder"
		if (these_items as text) contains "Name_Of_My_Thumbdrive" then -- (replace "Name_Of.." with name of the thumbdrive)
			set theThumbDrive to (first item of these_items) as text
			-- Put code to do the copying here
		end if
	end tell
end adding folder items to

Name and save the script (as an application) in /Users/Youracct/Library/Scripts .

Then open the AppleScript Utility in Applications/AppleScript/ .

In the AppleScript Utility,

  • click “Setup Actions”. in the dialog,
  • click “Enable Folder Actions”.
  • click the plus sign on the column labeled “Folders With Actions”. Choose any random folder (we will change this later) and click Open.
  • in the dropdown box, choose the script that you just saved. Click Attach.
  • now double-click the folder name that you chose, in the left column. It will become editable.
  • in the editable text box, type “Volumes”. This sets the folder action script to act when something is added to /Volumes.
  • close the AppleScript Utility.

Now whenever any volume is mounted, it will add an item to the /Volumes directory and will trigger your Folder Action Script. You can add a line

Tell app "Finder" to eject {volumeName}

To the guts of your script to unmount the thumb drive when it is finished copying.

This can be done even more elegantly with shell scripts and the “launchd” BSD facility. Anyone interested in this method post and I will describe it.

Model: Mac G5 Dual 2.0
AppleScript: 1.10.3
Browser: Safari 417.8
Operating System: Mac OS X (10.4)

Thank you so much. The following script works like a charm now:

on adding folder items to this_folder after receiving added_items
	tell application "Finder"
		if ("my_drive's_name") is in (name of disks) then
			duplicate file "Main_Drive:Users:username:Documents:folder:file" to folder "my_drive's_name:folder:" with replacing
              eject disk "my_drive's_name"
		end if
	end tell
end adding folder items to

The folder action process seems to be working for me. I insert the thumb drive, the file is copied, the drive is ejected, I pocket it and go. Perfect.

I next wanted to clean up my code a bit, get audio feedback instead of dialog boxes, and make it extendable to other drives. So I made the following changes that ended up breaking the code. Could you tell me why what I did doesn’t work? The script doesn’t find the drive anymore. I suspect the problem is in the syntax of the IF statement. This is probably one of those obvious solutions that is staring me in the face.


set drive_name to "my_drive's_name"

on adding folder items to this_folder after receiving added_items
	tell application "Finder"
		if drive_name is in (name of disks) then
			duplicate file "Main_Drive:Users:username:Documents:folder:file" to folder "my_drive's_name:folder:" with replacing
			say "file copied successfully"
			eject disk drive_name
			say "You may now pull out" + drive_name
		end if
	end tell
end adding folder items to

Johnny, just saw your post. I’m digesting it now. :wink:

Once I figure this out in applescript I would be very interested in learning about your shell script. Thanks.

First guess - when the script is triggered as a Folder Action, the entry point is the “On” statement, so it never executes the "set drive_name to “my_drive’s_name” statement.

Move that statement inside the ON handler.

LOL Did I mention I was a little rusty at this?

on adding folder items to this_folder after receiving added_items
	
	set drive_name to "my_drive's_name"
	
	tell application "Finder"
		if drive_name is in (name of disks) then
			duplicate file "Main_Drive:Users:username:Documents:folder:file" to folder "my_drive's_name:folder:" with replacing
			say "file copied successfully"
			eject disk drive_name
			say "You may now pull out" & drive_name
		end if
	end tell
end adding folder items to

Works like a charm again. Thanks.

Now that the script works I think I need to add some error checking. I found this link http://www.apple.com/applescript/folderactions/05.html that shows a very complicated backup script (#2 on the page). I’m not sure if I really want that much error checking, but I think checking for the presence of the original file would be a good idea. Can you suggest other areas this script might be missing? Thanks in advance.

Model: iBook G4
AppleScript: 1.10.3
Browser: Safari 417.8
Operating System: Mac OS X (10.4)

Definitely not a bad idea to make sure the file that is to be duplicated actually exists - if it doesn’t exist, the script won’t just malfunciton; it will bomb out with an AppleScript error. Always rather gauche.

There are two approaches to this:

  1. Use a Try … On Error … End Try block. This has the advantage of letting you also intercept the error in case it is some error OTHER than the file not existing.
  2. Just simply use an If … Then … Else … End If construct. This only tests for one scenario, that of the file not existing, but it is probably more than sufficient.

set theFile to "Main_Drive:Users:username:Documents:folder:file" as alias
if exists theFile then
duplicate file theFile to folder "my_drive's_name:folder:" with replacing
else
beep
display dialog "File " & (theFile as text) & " to be archived does not exist."
return
end if

Something like that. It may have some file/folder/alias/path errors - these are the bane of AppleScript and in 9 years I still don’t understand them.

So far so good. The script is shaping up nicely. Thanks for your input, Johnny. Aliases are a pain. I’m glad to hear somebody else has trouble with them. :confused: Not because misery loves company, but because I’ve been going crazy over here trying to get them to work. :rolleyes:


on adding folder items to this_folder after receiving added_items
	
	-- First set up the variables
	set drive_name to "USB Drive"
	set theFile to "Main_Drive:Users:username:Documents:file"
	set theDestination to "USB_Drive:folder:"
	set theBackup to "USB_Drive:folder:file" --To be used later
	
	tell application "Finder"
		if (drive_name as text) is in (name of disks) then
			
			if exists theFile then
				duplicate theFile to theDestination with replacing
				say "Congratulations" --Or something else to be decided later
				eject disk drive_name
				say "You may now pull out" & drive_name
			else
				beep
				display dialog "It appears that " & (theFile as text) & " does not exist. I'd be alarmed if I were you."
				return
				eject disk drive_name
			end if
			
		end if
	end tell
	
end adding folder items to

I’ve moved the original file and the error pops up nicely. (The beep doesn’t work, btw)

Now to be complete I wonder if I should add a routine to check to see if the destination folder exists (or would that matter?) and also to compare the modification date and time and filesize of the original file with the backup file and pop up an error if they aren’t the same (which would mean the backup failed for some reason). I’ve been playing around with the “modification date” property. Can you point me to some scripts that might show me how to make this comparison?

Model: iMac
AppleScript: 1.10.3
Browser: Safari 417.8
Operating System: Mac OS X (10.4)

This is the general idea:

set F to choose file without invisibles
tell application "Finder" to set M to modification date of F
set daysOld to ((current date) - M) div days

If the folder doesn’t exist, then the script will crash NOT at the duplicate statement, but at the variable assignment of the folder path.

To access the properties of a file or folder, use “info for”:

tell application "Finder"
	set x to alias "Tiger 10.4.6b:Users:johnny:Desktop:977.c"
	size of (info for x)
end tell

EDIT: So to compare the sizes,


set theBackedUpFile to alias "the:backed:up:file"
set theOriginalFile to alias "the:original:file"

set sizeOfBackup to size of (info for theBackedUpFile)
set sizeOfOriginal to size of (info for theOriginalFile)
set dateOfOriginal to modification date of (info for theOriginalFile)
set dateOfBackup to modification date of (info for theBackedUpFile)

if (sizeOfBackup is not equal to sizeOfOriginal) or (dateOfBackup is not equal to dateOfOriginal) then
display dialog "Sizes or times don't match - Tonto say something wrong."
end if

The Finder is a little kinder that that:

tell application "Finder" to set M to modification date of F -- gets a date
-- and
tell application "Finder" to size of F -- returns a floating point number

Thanks Adam.

I think this kind of thing is what drives people nuts working with AppleScript. How fabulous it could be if they would only write some CORRECT documentation.

Here is what you see if you look up “file” in the Finder Dictionary:

file‚n [inh. item] : every file
elements
contained by application, containers, disks, folders, desktop-objects, trash-objects.
properties
file type (type class) : the OSType identifying the type of data contained in the item
creator type (type class) : the OSType identifying the application that created the item
stationery (boolean) : Is the file a stationery pad?
product version (Unicode text, r/o) : the version of the product (visible at the top of the “Get Info” window)
version (Unicode text, r/o) : the version of the file (visible at the bottom of the “Get Info” window)

According to that, the only properties of a file are file type, creator type, stationery, product version, and version. That is just wrong. There is nothing there at all about size or modification date or dozens of other properties of a file. The programmer is left to trial and error.

I cannot understand what purpose these dictionaries serve. I have bought all of the AS books I can find, I use the Xcode documentation search, everything and after 9 years I still don’t understand why they don’t just have someone sit down and document this stuff. I subscribe to the AS users mailing list but finding anything in there is beyond hope - all of this stuff being discovered and yet no central reference manual for it.

I think the problem is that the dictionaries are waaaay out of date. When Apple updates things, they don’t seem to trickle down to the dictionaries. My usual approach is to “try the obvious”. If that fails, then I start digging.

[Edit} As an editorial comment, I can see how users who are trying to accomplish something find this very frustrating, but for me, a retiree dabbler, it just makes AppleScript more challenging and interesting. I think that might be true of several of the respondants to this bbs - they like to figure out how to make AppleScript do something. There are several others who have gone to the source - read all the tech notes that Apple publishes - and really understand exactly how AppleScript works. I’m not one of them.

Actually, the Search on MacScripter has been the single most useful and quick reference source for me.

I can almost always find a thread where someone was trying to do the same thing that I was stuck on.

I’m experimenting with making a PDF of all of the AppleScript User’s Mailing List messages and letting Spotlight find topics in there.

I’m a retiree dabbler too, and I remember the days when you bought a software app and it came with a 2-inch thick reference manual. I was one of the handful of people who actually sat down and read the thing cover to cover. If there were such a beast for AppleScript newer than 1999, I’d devour it, not stopping for meals or anything :lol:

I forget which textbook it is, maybe AS in a Nutshell, but chapter 19 in that book basically says up front that the Dictionaries are not useful. I agree. No examples, and don’t you just love when it says something like

firmit v. firmit an object

firmit (anything)

What do they mean, “anything”? Arrrgggghhhh…

Keep up the good work…

Johnny

Welcome fellow dabbler! May it lead to a fuller understanding of all things unwritten. Just bear in mind that there is a very fine line between “hobby” and “mental illness” - I have to remind myself of that.

I am very interested in hearing about the launchd method. Could you share your wisdom please?

Absolutely! Let me introduce it and later this afternoon I will post the step-by-step details.

“launchd” takes over most of the launching for what many Darwin daemons and apps do, although the old ones are still there.

launchd can do a lot, but for our purposes we will use launchd’s feature of being able to “watch” a directory just like Folder Actions, except a lot faster and more reliable. launchd scans its /Library/LaunchAgents directory every so often for periodic tasks (replacing crontabs), and is triggered by folder changes when told to watch a folder (adding items to, moving, etc).

To set up a launchd way to do what we did above in AppleScript, it is very simple. You need to do 2 things:

  1. Make a plist (XML) file telling launchd what you want done, and place it in either /Library/LaunchAgents or ~/Library/LaunchAgents, depending on whether you want to launchd action to run for all users or just for the user that owns the LaunchAgents directory where the plist resides.

  2. Write a short script, which can be AppleScript, shell script, Perl script, or even a compiled app. For this function of simply copying files, I recommend Perl or Bash. This can go anywhere you want, but most folks would put it in ~/Library/Scripts or /Library/Scripts, and you put its location in launchd’s plist.

Now, pertaining to #1 above, you COULD write launchd’s plist yourself using Property List Editor, but there is a free and handy full-featured GUI utility called Lingon which makes the plist file for you, based on what you choose in its GUI. This is definitely the way to go.

So until I get back to post the details, download Lingon from http://lingon.sourceforge.net/ and browse through the documentation in the Help menu.

Later,

Johnny

OK here is some more detail - first, regarding how to use Lingon to generate the plist that launchd uses:
Launch Lingon and set the following:

  1. From File, select New.
  2. Click the “My Agents” button in the dialog box. Click Create.
  3. In the Basic tab of the next dialog, type a label: com.salli.salliaction would be fine (any name that is unique is OK)
  4. Check the “On Demand” checkbox.
  5. In the “Program” text box, type “/Users/Youracct/Library/Scripts/yourScriptName.txt”, without quotes and substituting your Home folder name for “Youracct”.
  6. Click the Paths tab at the top of the window.
  7. In the WatchPaths box, type /Users/Youracct/Path/To/WatchedFolder, substituting the actual path to the folder you want launchd to watch. For the /Volumes folder, you just have to type /Volumes there.
  8. Click the Save and Reload button at the bottom.
  9. For good measure, click Reload and then quit Lingon.

Now write your script in any text editor (if you use TextEdit, remember to choose “Make Plain Text” before saving). Save it to /Users/Youracct/Library/Scripts/yourScriptName.txt .

Make the script executable by going into Terminal and typing

chmod +x /Users/Youracct/Library/Scripts/yourScriptName.txt

Remember, the script is only executed if launchd has detected an addition to the folder, so there is no need to put an “On adding items to…” block to the script, even if you code the script in AppleScript.

That’s it. You now have a plist file in your Library/LaunchAgents folder that tells launchd to watch the folder WatchedFolder in that path and to run the script /Users/Youracct/Library/Scripts/yourScriptName.txt whenever items are added to that folder.