test and runtime delay

Hi,
I need help for a bunch of little questions:
First one, this should be easy:

#test and echo
tell app "iTunes" to run
--
tell application "System Events"
	set a to "iTunes"
	set shared_fl to (bundle identifier of process a) & ".LSSharedFileList.plist"
end tell
--
set shfl to POSIX path of ((path to preferences folder as text) & shared_fl as text)
--do shell script "test -r '" & shfl & "' | 2>&1"
--do shell script "test -r '" & shfl & "' | echo"
try
do shell script "test -r '" & shfl & "'"
end

how to get the false and true value ? I don’t like too much the try-sequence.

Second one:
I wrote an applescript app (not studio) to open documents with a certain suffix with certain applications, (like what the action-button-wheel does in the Finder)
My problem wasn’t to code a compact code, but the runtime delay:

  • in Applescript editor, my code was executed in 0,5 seconds
  • as standalone App, my code exceeded 2 seconds for loading, running

What’s going on ?
I think it is late for my scripting experience, but I need to learn efficiently sorting routines. some hints ? thanks!

Hello


set a to "/a/pathto/posixfile"

set retval to (do shell script "test -r " & a & " && echo true  || echo  false") as boolean

As for the second one, try to run your script from within the run handler of the applet, that speeds things up. :wink:

The third; google for notes on sorting algorithms. You should know a thing or two about big O notation as well!

. which I think means: “Put your existing code into a script object and use the ‘run script’ command to execute it.”

script
	
	-- Script code here.
	
end script

run script result

Apart from the actual launching of the applet, most of your added time is taken up with the communication between the applications (your applet and whatever apps it’s telling to do things), which is quite slow. The above hack passes the script to ‘run script’ ” in the StandardAdditions OSAX ” to handle. This should speed things up a little because the communication time between OSAXen and applications is less than that between applications.

Another thing you can do is to make sure that as few individual commands are sent to the other applications as possible. If they can do things in bulk in response to a singe command, do it that way. And make sure the application ‘tell’ blocks only contain stuff which only the applications themselves can handle. That includes not nesting ‘tell’ statements to different applications.

There are my sorts at Softpedia, of course. :slight_smile: (I must update that package.) Or, if you’re not interested in how they work, Shane’s application and the Satimage OSAX have good sorting commands.

Hello!

It did mean exactly that! Kind of terse… They do write a lot of documentation over at Apple! No wonder why they call it a MacBook. And I’m in a hurry, I kind of qualified her to understand what I meant! :slight_smile:

Softpedia sounds very interesting. To have them all at one place! Thanks Nigel.

Check if the file exists and is readable you don’t need to invoke the test process because it’s a built-in function of bash.

set fp to quoted form of POSIX path of ((path to desktop folder) & "example.csv" as string)
(do shell script "fp=" & fp & "; [ -r \"$fp\" ] && echo true || echo false") as boolean

Hello!

I want to amend a little about the run script:

I have my scripts in a folder with the name of the script, then I have a product folder where I store the final version in. (latest save, after I have saved it with a number in the regular folder).

Then I have a stub in the script menu that loads it and runs it, with no particular added slowness. The real script never enters the script menu.

Then I can use that stub, to make an applet, and I can paste the same stub into an Automator Service.

The result is that I have Spotlight access, a keyboard shortcut and access through the script menu, and no wondering about where the latest version really is.

This an approach I have found to work good for me, with regards to organizing code. That this approach is (almost) the fastest way to run the script, doesn’t make it less usable.

(I removed the superfluos hyphens of my do shell script in the post above.)

This is the final version I came up with:

set aPosixFile to quoted form of "/a/posix/file"
set isReadable to (do shell script "[ -r  " & aPosixFile & " ]  && echo true  || echo  false ") as boolean

That looks indeed better as suggested.

Yes, and the “pattern” is usable for all the other test tests too!

I was marveled first, when I realized I didn’t have to quote true and false, then that the quoted form of the filname sufficed within the test.

For the record: I think it is correct to inform people when the brackets are used, so they know what man page to consult at least.

Thanks for the cooperation!

Brilliant!

I’ve just written a test script which individually reads the subjects of all the messages in my Read Mail folder in PowerMail, ten times. It takes 26 seconds to complete when run from Script Menu. The very same script takes only 3.5 seconds when run with ‘run script’ by another script in Script Menu.

PowerMail has its own scripts menu and the test script takes less than a second when run from that. But I find it more convenient to run all scripts from Script Menu, so your idea’s certainly worth looking into! :cool:

Did you also know that using double brackets you don’t need to quotation at all when using shell variables?

set fp to quoted form of POSIX path of ((path to desktop folder) & "it's value.txt" as string)
(do shell script "fp=" & fp & "; [[ -r $fp ]] && echo true || echo false") as boolean

Correct! the brackets can, as you discovered, be used as described in chapter ‘CONDITIONAL EXPRESSIONS’ of the bash man page(25).

Always a pleasure

Hello!
@ DJ Bazzie Wazzie I try to avoid using the most arcane constructs, but I think the double brackets may be useful! :wink:

I wrote some handlers out of the most useful ones of the tests.


set aPosixFile to quoted form of "/a/posix/file"

on isReadable for aPosixFile
	return (do shell script "[ -r  " & aPosixFile & " ]  && echo true  || echo  false ") as boolean
end isReadable

on isExisting for aPosixFile
	return (do shell script "[ -e  " & aPosixFile & " ]  && echo true  || echo  false ") as boolean
end isExisting

on isNewer for posixFileA against posixFileB
	return (do shell script "[ " & posixFileA & " -nt " & posixFileB & " ]  && echo true  || echo  false ") as boolean
end isNewer

on isOlder for posixFileA against posixFileB
	return (do shell script "[ " & posixFileA & " -ot " & posixFileB & " ]  && echo true  || echo  false ") as boolean
end isOlder

on isSame for posixFileA against posixFileB
	return (do shell script "[ " & posixFileA & " -ef " & posixFileB & " ]  && echo true  || echo  false ") as boolean
end isSame

And I wrote a general stub, with some builtin “make functionality” since the not all of you are having SDD disks. The idea is to use the stub as a clipping, that gets pasted into a script in the script menu, and an app, or an Automator Service later, but my intention is to check the date for the script against the stub in the script menu, so I won’t change anything concerning names, when pasting into an app or Automator Service. I you have other needs, you will have to do so yourself, regarding what to test against, and what to touch, which just updates the date of the script.

When I started doing this, it was for saving me the grief of editing the wrong script, and have some form of version control, that suffices in most cases. Here it is, it is not perfect, but it works. It reloads the script if you edit it.


” © McUsr 2012 and put in public domain! You are not allowed to post this elsewhere, nor in a publicly accessible repository
” Please refer to this post: http://macscripter.net/edit.php?id=156009
property tlvl : me
property hfsTlvlName : "hfspath:to:the:stub"
property hfsScriptName : "hfspath:to:the:real:script"
property scriptToRun : load script (hfsScriptName as alias)

if isnewer for quoted form of POSIX path of hfsScriptName against quoted form of POSIX path of hfsTlvlName then
	
	set my scriptToRun to load script (hfsScriptName as alias)
	do shell script "touch " & quoted form of POSIX path of hfsTlvlName
end if

tell scriptToRun to run

on isnewer for posixFileA against posixFileB
	return (do shell script "[ " & posixFileA & " -nt " & posixFileB & " ]  && echo true  || echo  false ") as boolean
end isnewer

I must also add that I usually encapsulate my script into a script within, using the same tlvl construct and such there to get library references. so if My script looks anything like this:


script myscr
property parent : AppleScript # Essential if you store script object in variables, for minimizing the context of the script object. (Which eats memory!)
# .
end myscr
tell myscr to run # so I can run it from the editor

Then the load statments look like this


property theScr to myscr of (load script ("hfs:path:to:myscript" as alias ))

I find this convenient. :slight_smile: I am glad you liked it Nigel!

Edit

The thing I find most convenient about it, is that now for instance, I had a script object that arranged say a TextEdit window a certain way, then I can just use that as a script object from within other scripts, reducing the need to edit a whole lot when I am to change something, but manage to seclude details to certain scripts much better!
Kind of object-oriented scripting. :slight_smile:

If you load script objects automatically and hierarchical I use an global variable for it. I also store scripts in an plugin folder with an bundle identifier to load the latest version of the scripts stored in the plugin.

global scriptObject

try
	scriptObject
on error
	set pathToBundle to pathToLatestBundle()
	if pathToBundle is missing value then error -1725
	set scriptObject to load script file (pathToBundle & ":Contents:Resources:scriptObject.scpt")
end try

on pathToLatestBundle()
	set pathToBundles to paragraphs of (do shell script "mdfind \"kMDItemCFBundleIdentifier == com.company.AppleScriptBundle\"")
	set theBundle to missing value
	set latestVersion to 0.0
	repeat with thePath in pathToBundles
		set currentVersion to short version of ((info for POSIX file thePath) & {short version:"0.0"}) as real
		if currentVersion > latestVersion then
			set theBundle to POSIX file thePath as string
			set latestVersion to currentVersion
		end if
	end repeat
	return theBundle
end pathToLatestBundle

The global holding the script object can be loaded anywhere. When there is another script object defining the same global and try to load scriptObject as well it doesn’t load it because it’s already loaded.

The script object is located inside an plugin. The reason for this is that I can give a bundle of scripts a version number, name and bundle identifier. The bundle identifier I use to determine where the bundle is locate so it doesn’t need a fixed placed per se. I have an handler of minum version requirements as well but didn’t show it here. Plugins are created quite easy

#file hierarchy according to the example code above

The info.plist file only need to contains:

The try catch is used to determine if the variable is set. When you launch the script you need to reset those value because they’re persistent. Emptying variable can be done quite easy


set var to void()

try
	var
	return true
on error
	return false
end try

on void()
end void

Hello.

That is an interesting approach.

I really want to keep things as simple as possible. I am lazy. Code will and does break, when I edit stuff. So I only use my approach for script objects not libraries.

I have been working on a script (that I will finish some day :slight_smile: ), that makes a build list for a library. so that I can compile all the scripts that uses the library in one go. Since I then know I am having a revision-stop, and are detecting the culprits much easier. ( A batch build per library). But libraries aren’t loaded by some make functionality, because at times when I revise a library, it would render large parts of my scripts unusable.

My taxonomy is also such that all the libraries are also residing as projects, with a products folder, and aliased from there into a library folder, which is an approach that works well for me.

I don’t store script objects in globals, but tries to encapsulate whatever I can encapsulate, in order to not break dependencies or create name conflicts. This may lead to larger scripts, but I believe firmly that each library, and script object should be looked upon as a black box, and be an entity in its own right.

Neither do I collect scriptObjects as a separate entity that I can load from a specified location. That would lead to the copying, and extranous work and maybe culprits, that my approach with the products folder tries to avoid.

Say I want to edit a script.
I open the version that is there in the Script Editor.
I save it with a higher number, than any other, in the folder the versions reside.
I then edit, and I can run that edited version from one of the places. confident that it is the last version that are executed.

And that is all that is to it.

I do like your approach, and may use it, when things feels more stable. But I feel it would impose more work for me at least, as large parts of my codebase is unstable. :slight_smile:

Edit

I see now clearly…, that what I can do with the “libraries problem” for the future, is to start using version numbering of the libraries, and alias the versions in the scripts folder, using the library with the highest number for new scripts, and stick with the old version for the old scripts, until I edit them, and needs new functionality. Now, this would be the opposite of the scheme that I use for script objects, but it would work fairly well for script that is dependent on libraries.

-Because knowing you are breaking like 20 scripts because you start to change name on handlers, is kind of a deterrent! :smiley:

Thanks for your response, I’m lazy as well and therefore it’s an xcode project on my machine. One build button to compile as ‘execute-only’ scripts, put it in plugin with the info.plist file and also commit the project in SVN, all in one go.

Xcode is an amazing app, even more so with some homerolled build rules! :slight_smile:

Første;
thanks for the tip, MacUsr! I use some shell manuals, but they aren’t so complete showing code examples. I got it.

for my second question:
Nigel, its always a pleasure to read your posts. I understand what you mean with “Or, if you’re not interested in how they work.” but don’t be afraid. I’ll analyze and test your documentation step by step, to get a grasp from. Thank you for helping out !

supplement for iScripts:
-i corrected a bug preventing Applescript editor from saving files with strange names

I know iScripts is only a little app i created, but i think it does something useful. Obviously, i’ve no programming background to pretend a further development, like to switch to Xcode.
OMBazzie, i get a gooseskin every time i see the code you post! :cool:

Hello.

What I think I meant that it is not everybody who understand that the test command in particular can be expressed by a couple of brackets. It isn’t totally intuitive.

It takes time to make something, it is a bit like potatoes, they have to mature. And we all have different ways of working I guess.

If your main intent is scripting, then I recommend switching to ScriptDebugger. DJ Bazzie Wazzie does a lot of stuff besides scripting. And XCode isn’t that good for scripting by itself.

I am going to test your app! :slight_smile: