Searching AppleScripts

As I accumulate more and more scripts and fail repeatedly to make their names sufficiently meaningful when I save them, I am really missing some means of searching the content of scripts for the fragments I know I’ve used before. Unless scripts are specifically saved as text, they aren’t mass searchable with BBEdit or Spotlight (which I find damned near useless anyway - BBEdit is the only way to search document text contents in my view).

I’ve been considering this: A script that would “crawl” my ~/Library/Scripts folder (and all its internal folders) identifying those files that are saved as .scpt or as AppleScript .apps (not too hard), opening them in the Script Editor, and resaving them as .txt files (the default is .AppleScript, but I’d change that, and possibly change the owner to BBEdit) in a parallel set of folders in ~/Documents. My text set of nested folders would have a structure that matched the hierarchy in ~/Library/Scripts. I’d let this run all night the first time and log errors - opening every script or aplet, saving as text, closing, etc.

Later, to look for some fragment, I’d script BBEdit to search my Script Text folder for the key words I wanted. To avoid having to periodically run my AppleScript Texter, I’d have to remember to save the text copy every time I saved the script, or write a folder action that would do that.

Has anyone done this or something like it?

I have a script that works on a test folder, but somethings not right when I try to make run over the entire scripts folder.

I’m in the same boat, still struggling to get the entire contents of the Script folder organized. Are you willing to share your version which sounds much more successful than mine?

First, here’s the script I just made:

property sourceFolder : POSIX path of (path to scripts folder as text)
property targetFolder : POSIX path of ((path to documents folder as text) & "Scripts")

do shell script "mkdir -p " & quoted form of targetFolder & ¬
	"; cd " & quoted form of sourceFolder & ¬
	"; cp -Rfp * " & quoted form of targetFolder
do shell script "find " & targetFolder & " -iname *.applescript -exec rm -f {} \\;"
do shell script "find " & targetFolder & " -iname *.scpt -or -iname *.app | grep -iv '.app/'"
set fileList to result

if result is "" then
	display dialog "No compiled scripts or applications were found." buttons "Cancel" default button 1
else if result does not contain (ASCII character 13) then
	set fileList to fileList as list
else
	set ASTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to (ASCII character 13)
	set fileList to every text item of fileList
	set AppleScript's text item delimiters to ASTID
end if

try
	set ASTID to AppleScript's text item delimiters
	tell application "Script Editor" to launch
	
	repeat with thisFile in fileList
		set AppleScript's text item delimiters to "."
		
		get POSIX file thisFile
		tell application "Script Editor" to open (result as alias)
		
		set newFile to POSIX file (((text items 1 through -2 of thisFile) as text) & ".txt")
		set AppleScript's text item delimiters to ""
		
		tell application "Script Editor"
			save front document as "text" in newFile
			close front document
		end tell
		
		do shell script "rm -rf " & quoted form of thisFile
	end repeat
	
	set AppleScript's text item delimiters to ASTID
on error errorMsg number errorNum
	set AppleScript's text item delimiters to ASTID
	display dialog "Error (" & errorNum & "):" & return & return & errorMsg buttons "Cancel" default button 1 with icon caution
end try

I didn’t think of it earlier, but this is going to copy existing text files to the new folder. This can be handled later.

The problem I’m having with running this on my whole script folder is that “find” is not finding everything.

Edit: I had tried seperating the find command earlier, but I think I made a typo while doing so. Now it finds everything as expected. I’ll test some more.

Edit: Added line to remove the .applescript files that get copied. If you have any other files that you don’t want copied, you’ll have to handle that (until I come up with a better way to copy files).

Instead of:

do shell script "mkdir -p " & quoted form of targetFolder & ¬
"; cd " & quoted form of sourceFolder & ¬
	"; cp -Rfp * " & quoted form of targetFolder & ¬
	"; find " & quoted form of targetFolder & " -iname *.scpt -or -iname *.app | grep -v '.app/'"

I ran this successfully:

set fldr to POSIX path of (choose folder) -- I chose my own ~/Library/Scripts Folder here
do shell script "find " & quoted form of fldr & " -iname *.scpt -or -iname *.app | grep -v '.app/'"
set fileList to result

Also, this works if I run it the script inside Script Editor, but if I try to run it from the script menu, I get an error (#1): NSReceiverEvaluationScriptError: 4.

If this helps, this code works fine for me. There are some effect-sides: it will re-create the hierarchy of app-bundles, it will launch any needed application to get the source, etc. But it works pretty fast for a basic transformation. Requires Jon’s Commands:

property sourceFolder : path to scripts folder as text
property targetFolder : (path to documents folder as text) & "Scripts:"

do shell script "mkdir -p " & quoted form of POSIX path of targetFolder
set all to paragraphs of (do shell script "find " & quoted form of POSIX path of sourceFolder)

process(all)

to process(flst)
	script a
		property o : flst
	end script
	
	repeat with i from 1 to count flst
		set scr to a's o's item i as POSIX file
		try
			set scptSrc to (load script scr) as text
			saveIt(scptSrc, scr)
		end try
	end repeat
end process

to saveIt(txt, f)
	--> get info to re-create in targetFolder
	set AppleScript's text item delimiters to sourceFolder
	set fRelativePath to item -1 of ((f as text)'s text items)
	set AppleScript's text item delimiters to ":"
	set fPath to "" & items 1 thru -2 of fRelativePath's text items & ":"
	set AppleScript's text item delimiters to {""}
	
	set finalFile to (targetFolder & fRelativePath & ".txt")
	
	try
		(targetFolder & fPath) as alias
	on error
		do shell script "mkdir -p " & quoted form of POSIX path of (targetFolder & fPath)
	end try
	
	set q to (open for access file finalFile with write permission)
	set eof of q to 0
	write txt to q
	close access q
end saveIt

Lines like:

always blow me away. Brisk, efficient and fast.

Thanks to everyone for discussing this. I’d long been meaning to cook up something similar for myself. When I saw jj’s slightly faster ” and very much shorter ” script, I decided not to post my own. But I believe mine may be immune to the bundle hierarchy problem and it doesn’t omit scripts that are in the root folder of the Scripts folder, so here it is. It handles script/text files saved by any of the three main script editors and assumes that any applications in the hierarchy are AppleScript applets or droplets. The saved text files have “.txt” tagged onto the original files’ full names and their owner is set to BBEdit, as per NovaScotian’s original idea. Works in Jaguar and Tiger. Needs Jon’s Commands for the script-to-text coercions.

Its great length (sorry!) is due to the fact that the code that sorts out the scripts ” ‘main()’ ” is tagged onto a hierarchy duplicating script that I wrote earlier in the year, which in turn uses a previously existing vanilla sort handler. jj’s idea is much simpler. :wink:

(Edited 7th October 2005 to show a later version of the script.)

on run
	considering case
		scripts2text()
	end considering
end run

-- The main handler.
on scripts2text()
	-- Create an empty copy of subject folder hierarchy in the user's Documents folder.
	try
		if (keys pressed) contains {"Command"} then -- 'keys pressed' requires Jon's Commands.
			set rootPath to (choose folder with prompt "Select a folder or hierarchy containing scripts...") as Unicode text
		else -- Default to user domain Scripts folder.
			set rootPath to (path to scripts folder as Unicode text)
		end if
	on error number -1708
		showMessage("This script requires the" & return & ""Jon's Commands" OSAX.", stop, 10)
	end try
	set destinationPath to (path to At Ease documents folder as Unicode text)
	set newRootPath to duplicateHierarchy(rootPath, destinationPath)
	
	-- Get a list of all the script files (ie. files saved by SE, Smile, or SD), applets, and droplets, and script bundles in the Scripts folder hierarchy.
	set likelyCreators to {"ToyS", "VIZF", "asDB", "aplt", "dplt", missing value}
	tell application "Finder"
		try
			set scriptFiles to (files of entire contents of folder rootPath whose creator type is in likelyCreators) as alias list
		on error
			set scriptFiles to (first file of entire contents of folder rootPath whose creator type is in likelyCreators) as alias as list
		end try
	end tell
	if scriptFiles is {} then showMessage("No script files were identified in this folder.", stop, 10)
	
	-- Prepare the TIDs for changing the root sections of the file paths.
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to rootPath
	
	-- Some applications may launch when scripts that target them are opened. Disks may be mounted.
	-- Note the apps that are open now and count the current disks.
	tell application "System Events" to set previousAppNames to name of application processes
	set diskCount to (count (list disks))
	
	-- Process the returned files.
	set scriptsDone to 0
	repeat with thisFile in scriptFiles
		try
			-- If this is an editable script, get the source code.
			set txt to (load script thisFile) as text -- The coercion requires Jon's commands.
		on error m number n -- -1752, -1700, -43
			if (n is -1752) then
				-- Otherwise, if it's a text file, get the text.
				set txt to (read thisFile as text from 1)
			else if (n is -1700) then
				-- If it's a run-only script, write an explanatory note.
				set txt to "The original of this file may be a run-only script."
			else
				-- Otherwise set a zero-length string to bypass the following 'if'.
				set txt to ""
			end if
		end try
		
		if ((count txt) > 0) then
			-- Get the path of this file.
			set thisFilePath to thisFile as Unicode text
			-- Zap the trailing colon if it's a package. (The Finder didn't return folders or disks.)
			if (thisFilePath ends with ":") then set thisFilePath to text 1 thru -2 of thisFilePath
			-- Cut the root of the path and check the rest for slash characters. (Replace with bars.)
			set hierarchyPath to (text from text item 2 to -1 of thisFilePath)
			if hierarchyPath contains "/" then
				set AppleScript's text item delimiters to "/"
				set hierarchyPath to hierarchyPath's text items
				set AppleScript's text item delimiters to "|"
				set hierarchyPath to hierarchyPath as Unicode text
				set AppleScript's text item delimiters to rootPath
			end if
			-- Assemble the path to the target text file.
			set savePath to newRootPath & hierarchyPath & ".txt"
			-- Write the text to a file at the new location.
			set f to (open for access file savePath with write permission)
			try
				write txt to f
			end try
			close access f
			
			-- Every 10 scripts processed, beep to show the script's still working
			-- and close any target apps that have been launched.
			set scriptsDone to scriptsDone + 1
			if (scriptsDone is 10) then
				beep
				quitOpenedApps(previousAppNames, false)
				set scriptsDone to 0
			end if
		end if
	end repeat
	
	set AppleScript's text item delimiters to astid
	
	-- Make BBEdit the owner of the saved text files.
	tell application "Finder" to set creator type of files of entire contents of folder newRootPath to "R*ch"
	-- Close any remaining launched apps.
	quitOpenedApps(previousAppNames, true)
	repeat with i from diskCount + 1 to (count (list disks))
		tell application "Finder" to eject disk i
	end repeat
	
	showMessage("Done!", note, 5)
end scripts2text

-- Display a message with the required icon for the required time. Quit if stop icon.
on showMessage(msg, iconType, maxTime)
	beep 2
	tell application (path to frontmost application as Unicode text)
		display dialog msg buttons {"OK"} default button 1 with icon iconType giving up after maxTime with title "Scripts2Text"
	end tell
	if (iconType is stop) then error number -128
end showMessage

-- Quit any apps that have been opened during the process, unless Classic has been started too.
on quitOpenedApps(previousAppNames, scriptFinishing)
	tell application "System Events" to set ClassicNotRunning to (not ((application process "Classic Support") exists))
	if (ClassicNotRunning) or (previousAppNames contains {"Classic Support"}) then
		-- If Classic hasn't been started during this script, close any newly opened applications.
		tell application "System Events" to set currentAppNames to name of application processes
		repeat with thisname in currentAppNames
			if (thisname is not in previousAppNames) then
				tell application thisname
					try
						activate -- Necessary in Jaguar.
						quit
					end try
				end tell
			end if
		end repeat
	else
		-- If Classic has been started during this script, don't do anything unless 'scriptFinishing' is flagged as true.
		if (scriptFinishing) then
			-- Otherwise, quit Classic, delaying till it's gone.
			tell application "Classic Support" to quit
			tell application "System Events"
				repeat while ((application process "Classic Support") exists)
					delay 0.5
				end repeat
			end tell
			-- When it's gone, quit any other opened apps too.
			quitOpenedApps(previousAppNames, scriptFinishing)
		end if
	end if
end quitOpenedApps

-- The remaining handler
on duplicateHierarchy(rootPath, destinationPath) -- params: HFS paths as Unicode text.
	-- Script object for customising CustomQsort.
	-- (Straight comparisons. No shadow actions on swaps & shifts.)
	script o
		on isGreater(a, b)
			(a > b)
		end isGreater
		
		on isLess(a, b)
			(a < b)
		end isLess
		
		on swap(a, b)
		end swap
		
		property shift : swap
	end script
	
	-- Combine the paths of all the folders in the hierarchy into one, delimited string.
	-- The path to the root folder will be contained in all the other paths, 
	-- unless it's the only folder in the hierarchy.
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to ":"
	set newRootName to rootPath's text item -2
	repeat -- until no name clash with any existing folders at this destination
		try
			(destinationPath & newRootName) as alias
			set newRootName to newRootName & " copy"
		on error
			exit repeat
		end try
	end repeat
	set newRootPath to destinationPath & newRootName & ":"
	
	set AppleScript's text item delimiters to ASCII character 0
	try
		-- Get the path strings of every subfolder in the existing hierarchy.
		tell application "Finder" to set theHierarchy to every folder of entire contents of folder rootPath as Unicode text
		set theHierarchy to theHierarchy's text items
		-- Sort the paths lexically. This sorts subfolders immediately after their parents.
		considering case
			CustomQsort(theHierarchy, 1, -1, o)
		end considering
		-- Parse the hierarchy into a 'mkdir' specification based on the path to the new root folder.
		set mkdirString to makeMkdirString(theHierarchy, newRootPath)
	on error -- the root folder has no subfolders
		set mkdirString to ("mkdir -p " as Unicode text) & quoted form of POSIX path of newRootPath
	end try
	set AppleScript's text item delimiters to astid
	
	-- Create the new hierarchy.
	do shell script mkdirString
	return newRootPath
end duplicateHierarchy

-- Parse a sorted list of path strings to folders in a hiercharchy.
-- Use the *name* of each folder to build a new hierarchy specification for 'mkdir'.
on makeMkdirString(sortedList, newRootPath)
	script o
		-- Assign the list to a script object property for fast, referenced access.
		property pathList : sortedList
		-- Another list to collect the 'mkdir' specification parts.
		property outputComponents : {}
		-- Some pre-defined stuff in variables for speed.
		property singleQuote : "'" as Unicode text
		property slashQuote : "/'" as Unicode text
		property slashBraceQuote : "/{'" as Unicode text
		property comma : "," as Unicode text
		property quoteComma : "'," as Unicode text
		property braceComma : "}," as Unicode text
		
		-- A recursive subhandler that analyses how the paths relate to each other
		-- and decides how to structure the 'mkdir' string.
		on parse(a, b)
			-- At each recursion, items a thru b of the list are sibling folders and their descendents.
			-- Since each sibling is sorted immediately before its own descendents, item a is an immediate
			-- child of the previous level and may or may not have its own descendents and/or siblings.
			set basic to item a of my pathList
			if (a = b) then
				-- This is a childless subfolder with no later siblings. Append "/'<name>'," to the output.
				addNameToList(basic, slashQuote, quoteComma)
			else
				if (item b of my pathList begins with basic) then
					-- This folder has descendents but no later siblings. Append "/'<name>'" to output.
					addNameToList(basic, slashQuote, singleQuote)
					set closingBraceRequired to false
				else
					-- This folder is the first of siblings. May or may not have children. Append "/{'<name>'" to output.
					addNameToList(basic, slashBraceQuote, singleQuote)
					set closingBraceRequired to true
				end if
				set x to a + 1
				repeat with i from x to b
					-- Loop while the following paths denote descendents of the current sibling.
					if (item i of my pathList begins with basic) then
					else
						if (i > x) then
							-- If there are any, recurse to sort out the immediate subfolders and *their* descendents.
							parse(x, i - 1)
						else
							-- Otherwise, just append a comma to the output.
							set end of my outputComponents to comma
						end if
						-- Append the next sibling's name, in quotes, and continue the repeat.
						set basic to item i of my pathList
						addNameToList(basic, singleQuote, singleQuote)
						set x to i + 1
					end if
				end repeat
				-- At the end of the repeat, sort out any descendents of the last sibling.
				if (x > b) then
				else
					parse(x, b)
				end if
				-- Append a closing brace and a comma to the output if there were siblings at this level.
				if (closingBraceRequired) then set end of my outputComponents to braceComma
			end if
		end parse
		
		-- Another subhandler that parses the folder name from the supplied path string,
		-- UNIXifies any instances of "/" or "'", and appends to result to the output.
		on addNameToList(str, startQuote, endQuote)
			set str to str's text item -2
			if (str contains "/") then
				set AppleScript's text item delimiters to "/"
				set str to str's text items
				set AppleScript's text item delimiters to ":"
				set str to str as Unicode text
			end if
			if (str contains "'") then
				set AppleScript's text item delimiters to "'"
				set str to str's text items
				set AppleScript's text item delimiters to "'\\''"
				set str to str as Unicode text
				set AppleScript's text item delimiters to ":"
			end if
			
			set end of my outputComponents to startQuote & str & endQuote
		end addNameToList
	end script
	
	-- *The main part of makeMkdirString().*
	-- Set AppleScript's TIDs to ":" and call the recursive handler in the script object to arrange the output.
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to ":"
	considering case
		tell o to parse(1, count sortedList)
	end considering
	
	-- Coerce the resulting list to Unicode text and tidy up the result.
	set AppleScript's text item delimiters to ""
	set mkdirString to o's outputComponents as Unicode text
	set mkdirString to text 1 thru -2 of mkdirString
	set AppleScript's text item delimiters to ",}"
	set mkdirString to mkdirString's text items
	set AppleScript's text item delimiters to "}"
	set mkdirString to mkdirString as Unicode text
	set AppleScript's text item delimiters to astid
	
	-- Return the constructed hierarchy string, appended to the POSIX path of the new base folder.
	return ("mkdir -p " as Unicode text) & text 1 thru -3 of (quoted form of POSIX path of newRootPath) & "'" & mkdirString
end makeMkdirString

-- CustomQsort by Arthur Knapp and Nigel Garvey.
-- Params: a list, the start and end indices of the range to be sorted, a script object containing comparison handlers.
on CustomQsort(theList, l, r, compObj)
	script o
		property cutoff : 10
		property p : theList
		
		on qsrt(l, r)
			set i to l
			set j to r
			set v to my p's item ((l + r) div 2)
			
			repeat while (j > i)
				
				set u to my p's item i
				repeat while (compObj's isLess(u, v))
					set i to i + 1
					set u to my p's item i
				end repeat
				
				set w to my p's item j
				repeat while (compObj's isGreater(w, v))
					set j to j - 1
					set w to my p's item j
				end repeat
				
				if (i > j) then
				else
					set my p's item i to w
					set my p's item j to u
					
					compObj's swap(i, j)
					
					set i to i + 1
					set j to j - 1
				end if
			end repeat
			
			if (j - l < cutoff) then
			else
				qsrt(l, j)
			end if
			if (r - i < cutoff) then
			else
				qsrt(i, r)
			end if
		end qsrt
		
		on isrt(l, r)
			set x to l
			set z to l + cutoff - 1
			if (z > r) then set z to r
			
			set v to my p's item x
			repeat with y from (x + 1) to z
				if (compObj's isLess(my p's item y, v)) then
					set x to y
					set v to my p's item y
				end if
			end repeat
			
			tell my p's item l
				set my p's item l to v
				set my p's item x to it
			end tell
			
			compObj's swap(l, x)
			
			set u to my p's item (l + 1)
			repeat with i from (l + 2) to r
				set v to my p's item i
				if (compObj's isLess(v, u)) then
					set my p's item i to u
					repeat with j from (i - 2) to l by -1
						if (compObj's isLess(v, my p's item j)) then
							set my p's item (j + 1) to my p's item j
						else
							set my p's item (j + 1) to v
							
							compObj's shift(j + 1, i)
							
							exit repeat
						end if
					end repeat
				else
					set u to v
				end if
			end repeat
		end isrt
	end script
	
	set listLen to (count theList)
	if (listLen > 1) then -- otherwise the handler will error
		-- Translate negative indices
		if (l < 0) then set l to listLen + l + 1
		if (r < 0) then set r to listLen + r + 1
		
		if (r = l) then
			-- No point in sorting just one item
		else
			-- Transpose transposed indices
			if (l > r) then
				set temp to l
				set l to r
				set r to temp
			end if
			
			if (r - l < o's cutoff) then
				-- Skip the Quicksort if cutoff or less items
			else
				o's qsrt(l, r)
			end if
			o's isrt(l, r)
		end if
	end if
	
end CustomQsort

Because Nigel Garvey’s version uses Jon’s Command: “set txt to (load script thisFile) as text”, it gets the script content without opening the application(s) the script “tells”. I haven’t tried this script on my own Scripts folder yet, but it looks good from that point of view. I’ll try it when I understand what it’s doing, and it’s well documented (thanks Nigel).

What I don’t get (among many other things requiring more study on my part) in this is how Nigel knew that “load script” was in Jon’s Commands. When I look at the dictionary for Jon’s Commands (3.0d3) I don’t see that and yet it works for me. I don’t see it on Jon Pugh’s site, either.

NovaScotian

I don’t know anything about Jon’s Commands, but if I had to guess, I’d say Standard Additions is loading the script, and Jon’s addition is coercing the resulting script object into a string.

I was never aware of “entire contents.”

Better than a guess, Bruce. Scripting Additions is loading the script and Jon Pugh is coercing it to text.

Resetting the owner with “entire contents” is really neat, I agree.

I remember At Ease from waaay back. Interesting that this works in OS X. It produces exactly the same result if the At Ease is omitted, i.e. it yields the path to ~/Documents/

I’m afraId the applications are still opened ” at least on my machines. I don’t think there’s anything that can be done about that. It’s just an annoying feature of many OS X applications. :frowning:

Everything above the ‘main()’ handler is to do with duplicating a folder hierarchy (without the files) in a different location. If you run the script twice, another duplicate hierarchy is created whose base folder’s name has “copy” appended to it, and so on. The code was written earlier this year when I learned about ‘mkdir’, the only Unix command I’ve come across so far that’s inspired me to want to use it. Not only is it faster than the Finder at creating new folders, but one single call also creates any non-existent folders in the path that you pass to it, which saves having to use script recursion to create a chain of folders. And not only that, but with a specially formulated string, it’s possible to create an entire folder hierarchy with just one call ” including any sibling subfolders and their descendants! My script puts such a string together and makes that one call, on the (untested) theory that it’s faster to edit a lot of text than it is to make several individual ‘mkdir’ calls.

I see you and Bruce have sorted that out now. ‘Load script’ is a command you might use to incorporate another script, or a library, into the one containing the command.

Jon’s Commands provides several coercions, or at least, used to before the OS X version. (I haven’t read the literature recently.) The most infamous was an automatic one from HFS path to file specification, which regularly caught people out. Most scripters would have Jon’s installed on their machines, and many would forget this and simply use a path where an alias or a file specification was required. They’d go crazy trying to work out why the scripts worked on their machines but not on any of their users’. :wink:

As for the ‘At Ease’ thing, that was the only way it would work up until Jaguar, unless you used the equivalent string parameter: ‘path to “docs”’. Something to do with the history of the command. It was the same with ‘At Ease applications’ and “apps”.

Thanks for the cogent reply. As always, most helpful.

Now what I’d like to add is a feature that recognizes that an application has been opened and after the script has been processed quits it. Otherwise, I end up with half my applications open at the same time and the whole process bogs down in swapping.

wouldn’t be easier to just open the script, copy X number of characters and then paste it into the “Safari Comments” in the Finder’s “Get Info” box?

Opening the script may cause other applications to launch, which is the problem we’re trying to avoid.

That may be easier to do than to advise on. :confused: On my machines, the script only opens four or five applications, so the following inserts work brilliantly for me:

-- Before the repeat in main().
tell application "System Events" to set previousAppNames to name of application processes

-- Do the business.

-- At the end of main().
tell application "System Events" to set currentAppNames to name of application processes
repeat with thisName in currentAppNames
	if (thisName is not in previousAppNames) then
		tell application thisName
			activate -- necessary in Jaguar, but not in Tiger
			quit
		end tell
	end if
end repeat

The applications are opened once and quit once. Once they’re open, they don’t need to be opened again, which makes the handling of subsequent targetting scripts faster.

If you need to quit apps more frequently, doing it after every script might slow the process more than you’d like. As a compromise, you could check for opened applications after processing a certain number of scripts. The following inserts make it quite pretty to watch on a fast machine:

-- Just before the repeat in main().
tell application "System Events" to set previousAppNames to name of application processes
set scriptsDone to 0

-- repeat with thisFile in scriptFiles
	-- Process the script file.
	
	-- Then:
	set scriptsDone to scriptsDone + 1
	if (scriptsDone is 10) then -- Check after, say, every ten scripts.
		quitOpenedApps(previousAppNames)
		set scriptsDone to 0
	end if
-- end repeat

-- At the end of main().
quitOpenedApps(previousAppNames)


-- Then a separate handler.
on quitOpenedApps(previousAppNames)
	tell application "System Events" to set currentAppNames to name of application processes
	repeat with thisName in currentAppNames
		if (thisName is not in previousAppNames) then
			tell application thisName
				activate -- necessary in Jaguar, but not in Tiger
				quit
			end tell
		end if
	end repeat
end quitOpenedApps

Impressive - I hadn’t thought to base the application cleanup on scripts done. That ought to manage their getting out of hand. I’ve integrated the application checking into the earlier script and will beat on it tonight (GMT - 3)

At some point, Nigel, (wearing my ScriptBuilders hat) it would be great to have this posted to ScriptBuilders. I think it has general utility, at least for those who’d like to use BBEdit to search the text of their scripts for the fragments they are looking for. When I have time, I’ll work on a script to check whether the text saved is current and if not, back up to text only those scripts that have changed since the last time this one was run. Simpler, of course, is to schedule a regular complete backup to searchable text this way when my box is otherwise idle (I never turn it off anyway).

OK. I’ll check its reaction to run-only scripts and packages, think what else needs to be done, and knock up a read-me file. I discovered a minor weakness (which doesn’t affect the current script) in the last line of ‘makeMkdirString()’ yesterday. I’ve now fixed that and will include the fix in the ScriptBuilders version. :slight_smile: