AppleScript: Execute command when timestamp on file changes?

Is it possible to write an AppleScript that will execute a command when the timestamp on a named file changes?

I’m working on an automation process with a Linux user and he has put something like this together for Linux and I’m wondering if the same can be done on a Mac.

The idea is to select a file, run a command on the file and then “listen” for a change in timestamp on that file. If the timestamp changes, then the command is run again against the named file, if it doesn’t change, the command is not re-run.

The main problem I see here is how would you then exit such a script/program once you were through with it?

Is it possible to write a script that you then export as an app, but which does not reply on a visible dialog to close (i.e. could it be closed at some point via cmd+Q?).

Many thanks,

Bowjest

I’ve found I can get the file timestamp using the following bash command:

stat file.docx | cut -d " " -f12
12:48:12

But when I try to convert this to AS, my syntax must be letting me down somewhere:

set default_folder_Location to (path to home folder as text) & "01 Translations:03 Projects:"
set theFile to (choose file with prompt "Choose file:" default location alias default_folder_Location)
set oldTimestamp to "stat " & quoted form of POSIX path of theFile & " | cut -d \" \" -f12"
do shell script "echo " & oldTimestamp

The result I get is just “”.

I thought the problem might be POSIX-related, so I then tried this:

set default_folder_Location to (path to home folder as text) & "01 Translations:03 Projects:"
set theFile to (choose file with prompt "Choose file:" default location alias default_folder_Location)
set theFilePOSIX to the quoted form of POSIX path of theFile
set oldTimestamp to "stat " & theFilePOSIX & " | cut -d \" \" -f12"
do shell script "echo " & oldTimestamp

If the script itself runs without an error (i.e. it doesn’t refuse to run because it sees an error in syntax), can anyone advise how I can troubleshoot this?

Thanks,

Bowjest

Hi,

The following works for me:

--set default_folder_Location to (path to home folder as text) & "01 Translations:03 Projects:"
set theFile to (choose file with prompt "Choose file:")
set oldTimestamp to "stat " & quoted form of POSIX path of theFile & " | cut -d \" \" -f12"
set x to do shell script oldTimestamp

The only real change is that I’m not "echo"ing the shell script!

Regards,
in-toto

The echo command just prints out rest of the line, to execute the stat command omit echo

do shell script oldTimestamp

Thanks in-toto and Stefan.

Before I saw your replies, I “fixed” the problem this way:

set default_folder_Location to (path to home folder as text) & "01 Translations:03 Projects:"
	set htmlFile to (choose file with prompt "File to convert:" default location alias default_folder_Location)
	set htmlFilePOSIX to the quoted form of POSIX path of htmlFile
	set oldTimestamp to (do shell script "stat " & htmlFilePOSIX & " | " & "cut -d \" \" -f12")

Is there a difference in how this is achieved (one better than the other)?

I’m almost there, but am unsure how to finish this.

What I’m trying to do is launch this script, select a docx file, check its time stamp, convert it to HTML and then, if the time stamp of the original docx file changes (has been updated), the conversion process is run again to created an updated HTML file. This would then set the newTimestamp as the oldTimestamp, waiting to see if there is a further update.

Here is what I have so far:

-- Script to update OmegaT projects for previewing
-- in the Opera browser. Written with the generous
-- advice of McUsr and StefanK at Macscripter.net

-- extend the default 2 minute timeout
with timeout of (30 * 60) seconds
	
	-- set path relative to home folder
	set default_folder_Location to (path to home folder as text) & "01 Translations:03 Projects:"
	set htmlFile to (choose file with prompt "File to convert:" default location alias default_folder_Location)
	set htmlFilePOSIX to the quoted form of POSIX path of htmlFile
	set oldTimestamp to (do shell script "stat " & htmlFilePOSIX & " | " & "cut -d \" \" -f12")
	
	tell application "Finder"
		reveal htmlFile
		do shell script "textutil -convert html " & htmlFilePOSIX
		tell application "System Events"
			tell application "Opera" to activate
		end tell
	end tell
	
	repeat
	
	set newTimestamp to (do shell script "stat " & htmlFilePOSIX & " | " & "cut -d \" \" -f12")
	
		if newTimestamp does not equal oldTimestamp then
		do shell script "textutil -convert html " & htmlFilePOSIX
		set newTimestampt to oldTimestamp
		tell application "System Events"
			tell application "Opera" to activate
		end tell
	end repeat
	
	
	-- end timeout
end timeout

It complains, however, about the “end repeat” in the repeat loop, saying “Expected end of line etc., but found repeat”

Surely I have to terminate the repeat, right? Otherwise, how will it know where the repeat starts and stops?

Thanks,

Bowjest

there is an end if missing before the end repeat line

System Events is not needed to activate an application


activate application "Opera"	

without the System Events tell block is sufficient

Thanks, Stefan. School boy error on my part. Was too concerned about the other aspects.

It works now, but strangely, it won’t let Opera go. Once Opera moves to the foreground, it’s like it loops over that and I can change focus to anything else. If I cmd+q out of Opera, it just launches it again.

I think I must have made a syntax error when making the newTimestamp the oldTimestamp. Do you know what I mean?

I assign a starting time stamp and then check for a new timestamp. If the “old” and the “new” aren’t the same, the conversion runs again and Opera comes to the fore. The “new” stamp then becomes the “old” so a future comparison can be made.

Perhaps this is the problem?

Regards,

Bowjest

there is a typo newTimestampt

but probably it’s the other way round


 set oldTimestamp to newTimestamp

Thanks, Stefan. Sorry, I’ve become a bit snowblind.

I fixed that and changed the variables as you indicated, but it’s still not letting me get away from Opera. If I quit out of Opera, it relaunches and after doing this twice I get the following error:

error “Opera got an error: Connection is invalid.” number -609

I don’t know what this means. Does it make sense to you?

Best,

Bowjest

Polling the file by calling the stat command a few hundred times per second isn’t a good idea anyway.

A better solution would be to monitor the parent folder with launchd for file system changes

Hmmmmm. I’m afraid I have no idea how to work with launchd.

All I know about it is that it is used to start the system and that Apple like it over the previous Linux things like rc and crontab, etc.

How would I use this to help me do timestamp comparisons?

Thanks,

Bowjest

launchd can observe folders for file system changes (similar to folder actions).
A file system change occurs for example when a time stamp of a file changes or a file is added or removed.
The notification can trigger a script to handle the event.

Unlike the polling solution notifications don’t consume CPU power.

Thanks. That does sound like the answer.

I’ll see if I can find some syntax examples. I’ll post what I find back here.

Bowjest

I found this on the forum, but I’ll need a good deal of time to try to understand it:

http://macscripter.net/viewtopic.php?id=24748

Bowjest

I see one problem with this option (please correct me if I’m wrong - which I probably am):

In the article (http://macscripter.net/viewtopic.php?id=24748) it says that launchd is watching the path (in the case of the article) /Volumes/, which is very high level and static. In my case, I will be working at a low level (project level) and as such, the path will be very long and dynamic.

The highest level that won’t change would be /Users/bowjest/01 Translations/03 Projects, but this is then subdivided by folders for customers, so have some dozen or so folders, each with their own data and project files.

If anything changes at the higher level, won’t this cause launchd to fire and try to carry out the contents of my script at the highest level (/Users/bowjest/01 Translations/03 Projects), thus trying to access all the data contained therein?

Thanks,

Bowjest

this is indeed a problem.
launchd can watch multiple folders but it’s not suitable for managing paths dynamically.

But with multiple folders I guess the polling solution will slow down the whole system.

With my script as it stands, the user would only ever select one file for the duration of the session.

If, for instance, I were working on a project (proofing corrections) for 20-30 mins or even an hour or more, the polling would only take place while I was working on that project.

This is why I initially used the button solution below:

-- extend the default 2 minute timeout
with timeout of (30 * 60) seconds
	
	-- set path relative to home folder
	set default_folder_Location to (path to home folder as text) & "01 Translations:03 Projects:"
	set htmlFile to (choose file with prompt "File to convert:" default location alias default_folder_Location)
	
	tell application "Finder"
		reveal htmlFile
		do shell script "textutil -convert html " & quoted form of POSIX path of htmlFile
		tell application "System Events"
			tell application "Opera" to activate
		end tell
	end tell
	repeat
		display dialog "Update HTML File" buttons {"Cancel", "Update"} default button "Update"
		do shell script "textutil -convert html " & quoted form of POSIX path of htmlFile
		tell application "System Events"
			tell application "Opera" to activate
		end tell
	end repeat
	
	
	-- end timeout
end timeout

But this requires the user to toggle to the app and hit return or click the update button.

I’ll see if the tcl/tk solution my colleague has written for Linux can be used with Macs as well without a lot of system overhead.

Thanks, Stefan. It’s always a learning experience when you lend a hand.

Bowjest

I’ve got the preview.tcl script to work by changing some parameters and running this:

wish preview.tcl target.docx

I’ve tried to update my script accordingly, but it fails to run correctly. Here is the script:

-- extend the default 2 minute timeout
with timeout of (30 * 60) seconds
   
   -- set path relative to home folder
   set default_folder_Location to (path to home folder as text) & "01 Translations:03 Projects:"
   set htmlFile to (choose file with prompt "File to convert:" default location alias default_folder_Location)
   set htmlFilePOSIX to the quoted form of POSIX path of htmlFile
	set previewTCL to (path to home folder as text) & "Library:Preferences:OmegaT:script:preview.tcl"
	
	tell application "Finder"
		reveal htmlFile
		do shell script "textutil -convert html " & htmlFilePOSIX
		tell application "System Events"
			tell application "Opera" to activate
		end tell
	end tell
	repeat
		display dialog "Update HTML File" buttons {"Cancel", "Update"} default button "Update"
		do shell script "wish " & previewTCL & htmlFilePOSIX
		tell application "System Events"
			tell application "Opera" to activate
		end tell
	end repeat
	
	
	-- end timeout
end timeout

The error I get is:

error “The command exited with a non-zero status.” number 1

Can anyone advise what the problem is? Does it need to print to console or something to work and that’s why it’s failing in script?

Thanks,

Bowjest

between previewTCL and htmlFilePOSIX must be a space character and previewTCL must also be a POSIX path.
The shell accepts only POSIX paths

I’ve gone back and assigned a POSIX path to the tcl script:

set previewTCL to (path to home folder as text) & “Library:Preferences:OmegaT:script:preview.tcl”
set previewTCLPOSIX to the quoted form of POSIX path of previewTCL

and tried to put a space after previewTCLPOSIX and the selected file, but it still fails:

do shell script "wish " & previewTCLPOSIX & " " & htmlFilePOSIX

error “The command exited with a non-zero status.” number 1

Is there some particular AppleScript variable I should be using to add a space between previewTCLPOSIX and htmlFilePOSIX?

Thanks,

Bowjest