Can a running script open another copy of itself?

This is something I’ve done before with php shell scripts, as a way of making them multi-threaded. The script calls a copy of itself with a command line argument, and that argument tells the script to run as a child process rather than a parent. Then the two scripts can communicate via messages in an sql database, reading and writing files in a folder, or any other way.

I’m wondering if something like this would work in applescript? Just out of curiosity, I don’t currently have any need to do anything like this. I’m just wondering if I could?

Yes you can. I’ve done it many times

How do you do it? and that question isn’t long enough so the forum is making me add some filler before I click Reply.

Here is a sample script…

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

on run argv
	path to me
	path to current application
	name of me
	if class of argv is list then
		if (count of argv) > 0 then
			if (item 1 of argv) is in {"clean", "CLEAN"} then
				clearError((item 2 of argv) as integer)
			end if
		else
			main()
		end if
	else -- no arguments passed so it is main app
		main()
	end if
end run

on main()
	local i, j, myPrefs, pid, cPath, temp, pcs, pm, tid
	set pid to do shell script "echo $PPID"
	set cPath to POSIX path of (path to me)
	set pid to do shell script "osascript '" & cPath & "' " & " CLEAN " & pid & " &>/dev/null & echo $!"  -- this runs the thread
	try
		tell application "loginwindow"
			set myres to display dialog "Sample dialog text?" buttons {"Cancel", "Mount", "Skip"} cancel button 1 default button 1 with title "Thread Dialog…"
		end tell
	on error
		set myres to {button returned:"Cancel"}
	end try
	delay 1
	try
		tell application "loginwindow" to display alert "Button \"" & (button returned of myres) & "\" was clicked!" giving up after 3
	end try
end main

on clearError(pid as integer)
	local i
	tell application "System Events" to tell application process "loginwindow" -- do GUI stuff here
		repeat with i from 10 to 1 by -1
			tell me to delay 1
			if window "Thread Dialog…" exists then exit repeat
			try
				do shell script ("ps -ax -o pid= " & pid)
			on error -- calling script is not running
				return
			end try
		end repeat
		if i = 1 then return -- timeout
		tell window "Thread Dialog…" to click button (some item of buttonList)
	end tell
end clearError

** EDIT ** – I added more logic to the clearError to test if calling script still running and a better timeout

Interesting. So the argument on on run argv is automatically there when your script is launched from the terminal and given an argument?

I can’t think of any use for this, but its cool you can do it.

I have a script that auto mounts shares that are saved in a preference file. I do this so the shares don’t start with an open window after being mounted. If an error occurs when mounting one of the shares, the OS shows an error dialog, which can’t be auto closed by the main script. So I have it run a second copy of itself to monitor if the error dialog appears. I do this using GUI scripting.

You can also create separate instances of script objects from text or a file.

@Piyomaru wrote a sample parallel application about 15 years ago, although it seems to have fallen off the end of Apple’s mailing list and his site archives. It basically created copies of an application’s bundle for use as separate processes. I have some pieces, but maybe he has archives that go further back.

I have done something like this, but with handlers, not scripts.
I do this when I am searching a folder tree of undetermined and unequal depth.
I usually start my script or application by setting up a few global variables, initializing properties and setting up script libraries.
Then I call what I call the execution handler whose job is to call the handlers which actually do the work. This strategy isolates the handlers from each other and from the run handler, except as specifically designated.
For a script searching the folder tree, I typically have a handler:
searchFolder(FolderReference, searchTarget, etc)
This returns searchResult, typically a list of records, each record is one search result.
If searchFolder() identifies any subfolders, it calls “searchFolder()” (itself) on each subfolder, and concatenates each result to its own searchResult list.