Help Please! Applescript monitor text file and run when updated

I am trying to write an apple script that will:

  1. Wait until a text file called “labview” receives a value of 1
  2. Then run the script
  3. Re-write to the labview file a value of 0.
  4. after it writes the value of 0, it should keep scanning the file “labview.txt” until the other program writes a value of 1 back to the file “labview.txt”
    Bascially, I have one program that runs and updates the file “labview.txt” Then the applescript should reconize that the file was update and then execute. After execution, it should write back to the file “labview.txt” so the other program can continue. The script I have so far is able to run correctly once, if I manually change the value of “labview.txt” be for telling applescript to run. If I try and change the value while the script is running, the script will not work correctly. I also keep getting an “end of file” error with the POSIX read command line. Here is what I have so far:

/Beginning of code

set dog to false

set logfile to “labview.txt”
set {lasteof, cureof, done, recentlog} to {0, 0, false, “”}

repeat until recentlog contains “1”

repeat while lasteof is cureof
	(*delay 1*)
	set cureof to get eof POSIX file logfile
end repeat
set recentlog to read POSIX file logfile from lasteof to cureof
set lasteof to cureof -- start next read at current location
set dog to true

end repeat

if dog is true then
tell application “Finder”
activate
open application file “Revolution” of folder “Revolution 1.6.0b148” of folder “Revolution” of folder “Applications” of startup disk
end tell

tell application "Extra Suites"
	
	ES move mouse {145, 55}
	ES click mouse with double click
	(*enter mag here*)
	set theText to "500"
	ES type string theText with use clipboard
	ES type key "return" with command
	
	set fileRef to (open for access file "labview.txt" with write permission)
	--> this will return a "reference number", which is similar to a stream,
	--> or just as the ticket you need to ride through the bytes
	
	--> the following will delete the contents of the file
	set eof of fileRef to 0
	write "0" to fileRef
end tell	

end if
/End of code

Thank you for your help

In my view, this problem cries out for a stay-open “on idle” application. Their structure is like this:

on run
– do stuff - this runs when the application is started (by double-clicking or otherwise) to set things up if need be. The on idle portion runs right after this, so an “on run” handler is not needed if the on idle does everything.
end run

on idle
– In this section, you periodically check your file and note it’s modification date. If it has changed since the last cycle, you do your thing.
return 60 – do this every 60 seconds (or whatever). The timing is provided by the system.
end idle

on quit
– do stuff - assumes you want some special action to follow quitting; otherwise not needed.
continue quit – if there’s an on quit handler at all, this line must be the last to be executed in it.
end quit

hi shive,

one thing i notice about your code is that you never ‘close’ the file when you are done with it. i wonder if that is the source of the error the next time your script runs?

I am still kind of confused on how to use the “on idle.” Will it monitor the text file, or will it only run when the text file changes? Also, how would I integrate the command into my script? would it replace the “repeat until” command. I tried to use the “close” command inside the “repeat until” section were it flags the “dog” boolean. Were do you suggest I place the “close” command. Thanks you guys, your life-savers.

I usually close files as soon as I’m through with them, so I would do this:

tell application "Extra Suites"
	ES move mouse {145, 55}
	ES click mouse with double click
	(*enter mag here*)
	set theText to "500"
	ES type string theText with use clipboard
	ES type key "return" with command
end tell -- don't need to be in tell block any more.
-- fix file
set fileRef to (open for access file "labview.txt" with write permission)
--> fileRef is a "reference number", which is similar to a stream,
--> or just as the ticket you need to ride through the bytes
--> the following will delete the contents of the file (if you write something)
set eof of fileRef to 0
write "0" to fileRef
close fileRef -- done with the file

The problem with repeat until a read of the file is “1” is that it’s compute intensive - the repeat loop is romping along waiting for the “1”.

Better technique is to write a separate “watcher” script (the on idle script) saved as a stay-open application and running when you’re doing whatever. It really is idle between cycles. When it detects the change in mod date or simply reads the file (you don’t have to open for access to read) and discovers the “1”, then it calls the script (a separate script) that does the rest. When that script is done, it quits, but the on Idle script doesn’t.

I don’t really understand what you’re doing, but this is one way to do what you said in your original post.

Ok, I was able to get it to monitor the text file. I have one last issue. When the Revolution program takes a picture, depending on the pixel size and dwell time, the time it takes to render the image changes. I tried an “is busy command” but could not get it to work. How could I tell the script that the Revolution program is still acquiring the image. The image opens in a new window to show you the “real time” progress of it. Is there someway I could tell applescripit to wait until that window closes to continue. The progress bar is just what I am using right now to pause the script, it is not tied to the Revolution software in any way. Here is what I have so far:
/begining of code
set dog to false
set monkey to false
set x to “labview1.txt”
(Change this to allow more time for picture acquiring)
set max to 88

repeat until monkey is true

delay 2

(*set s to alias (("/Users/admin/Dekstop/4pi script/labview1.txt"))*)

(*set s to alias ((path to "docs" as text) & "labview1.txt")
*)

set s to alias ((path to desktop from user domain as text) & "labview1.txt")

set f to read s

if f is equal to "1" then
	set dog to true
else
	set dog to false
	
end if


if dog is true then
	tell application "Finder"
		activate
		open application file "Revolution" of folder "Revolution 1.6.0b147" of folder "Revolution" of folder "Applications" of startup disk
	end tell
	
	tell application "Extra Suites"
		delay 1
		ES move mouse {145, 55}
		ES click mouse with double click
		(*enter mag here*)
		set theText to "500"
		ES type string theText with use clipboard
		delay 0.5
		ES type key "return" with command
		(*set dog to false*)
		delay 1

This is where I woudl like the script to pause and wait until the picture is acquiried and saved. If I could get that to work, I would get rid of the progress bar.

                 (*Don't adjust anything here*)
		(*This dislpays the progress baar*)
		ES display progress counting to max with caption "Acquiring"
		repeat with i from 1 to max
			set isCancelled to ES advance progress by 1 updating caption to "Acuiring Image"
			(*set isCancelled to ES advance progress by 1 updating caption to "Counting " & i & " of " & max*)
			delay 1
			if isCancelled = true then exit repeat
		end repeat
		ES close progress
	end tell
	set dog to false
	set desktop_ to path to desktop as Unicode text
	write_to_file("0", (desktop_ & "labview1.txt"), false)
	
end if

end repeat

to write_to_file(this_data, target_file, append_data)
try
set the target_file to the target_file as text
set the open_target_file to open for access file target_file with write permission
if append_data is false then
set eof of the open_target_file to 0
write this_data to the open_target_file starting at eof
close access the open_target_file
return true
end if
on error
try
close access file target_file
end try
return false
end try
end write_to_file
/end of code
Thank you guys for your help and time.

If the acquisition is building a file somewhere, the usual technique is to wait until that file stops growing:

set myFile to (choose file) as alias -- change to the file that's loading
-- get started
set firstSize to size of (info for myFile) --get initial size
delay 3 --wait 3 seconds -- or whatever you feel appropriate
set newSize to size of (info for myFile) --get a newer size, bigger if still acquiring
-- keep checking
repeat while newSize ≠ firstSize --if they don't equal, loop until they do
	set firstSize to newSize -- new base size for next comparison
	delay 3 --wait three seconds; or whatever as above
	set newSize to size of (info for myFile) -- get the latest size
end repeat --once the sizes match, the acquisition is complete

If the app waits until the acquisition is complete before storing the result
then you keep testing for the resulting file in a repeat block that exits with
an if exists file … then exit repeat

Thank you for all your help. I was able to get the script to work. My last question would be how do I stop the script once it saved as an application. I tried editing this script to stop it, but it did not work. I had two original approaches to this problem. The first one was to create a dialog box in the script which would display all the time and stop the script if the user pressed “OK”. My second approach, which I believe to be the better one is to have a second, script saved as an application, and use this script to stop the first script. Is this possible, since the first script, saved as an application, does not appear in the dock. The only to stop the script currently is to force quit it. Here is the code I have so far:
/Beginning of script
tell application “System Events” to set looping_command_running to (name of processes) contains “looping command”
if looping_command_running then
display dialog “4pi script is running. Shut down 4pi script Now?” buttons {“Cancel”, “Quit 4pi script now”} default button 2 with icon stop
if button returned of result = “Quit 4pi script now” then
tell application “looping command” to quit
– check every 3 seconds is 4pi is still running,
– since it needs some time until it is quit.
repeat while looping_command_running
tell application “System Events” to set looping_command_running to (name of processes) contains “looping command”
delay 3
end repeat
display dialog “4pi script is not running anymore!” buttons {“Quit”} default button 1
end if
end if
end
/end of script

Ok, I figured out what was causing the loop not to work, I had an extra space. Now I’ve got the script to work up until the “tell application “looping_command” to quit. I just hangs up and I have to use command + . to end the script. It gives me some kind of error like"looping_command got an error: User canceled out of wait loop for reply or receipt.”

Ok, got past that error. Now the script keeps going through the repat loop but never ends. It is like “looping_command” refuses to stop. Anyone have any ideas on how to fix this one.

I don’t get it. This works:

tell application "System Events" to if (name of processes contains "TextEdit") then if button returned of (display dialog "Quit TE?") = "OK" then tell application "TextEdit" to quit

Does it still work if you substitute the name of your script app and it’s running?

My theory is that it won’t because your app doesn’t have a dictionary so it doesn’t understand the quit command.
Perhaps it needs one of these:

on quit
continue quit
end quit

I tried that code, but it won’t work if I use “quit.” I had to change it to “stop.” Then the script would enter the repeat command. Maybe since the “looping_command” script has no “quit” or “stop” command it won’t work. Here is my code:
/Beginning of code
tell application “System Events” to set looping_command_running to (name of processes) contains “looping_command”
if looping_command_running then
display dialog “4pi script is running. Shut down 4pi script Now?” buttons {“cancel”, “Quit 4pi script now”} default button 2 with icon stop
if button returned of result = “Quit 4pi script now” then
(tell application “looping_command” to stop)
(NEEW CODE)
tell application “System Events” to if (name of processes contains “looping_command”) then tell application “looping_command” to stop

	repeat while looping_command_running
		tell application "System Events" to set looping_command_running to (name of processes) contains "looping_command"
		delay 3
	end repeat
	display dialog "4pi script is not running anymore!" buttons {"Quit"} default button 1
end if

else
display dialog “4pi script is not running.” with icon stop
end if
end
/end of code

Ok, I figured it out. Thank you guys for all the help. Here is the code if anybody else is having the same problem.
/Beginning of code
tell application “System Events” to set looping_command_running to (name of processes) contains “looping_command”
if looping_command_running then
display dialog “4pi script is running. Shut down 4pi script Now?” buttons {“cancel”, “Quit 4pi script now”} default button 2 with icon stop
if button returned of result = “Quit 4pi script now” then
tell application “System Events”
set theID to (unix id of processes whose name is “looping_command”)
try
– Should stop the application with no dialogs and no items saved.
do shell script "kill -9 " & theID
end try
end tell
repeat while looping_command_running
tell application “System Events” to set looping_command_running to (name of processes) contains “looping_command”
delay 3
end repeat
display dialog “4pi script is not running anymore!” buttons {“Quit”} default button 1
end if
else
display dialog “4pi script is not running.” with icon stop
end if
end
/end of code
Thanks again