Finding active applications to quit

The goal is a script that empties certain Cache folders; for example, the Cache folder that Eudora uses, that Safari uses, etc. That is accomplished by placing aliases to those folders on my desktop and successively emptying them. This task is very straightforward.

What is not straightforward is to find what applications are open, applications which use those Cache folders because I need to first quit these apps before I empty the corresponding folders.

The glich happens with:
tell application thisAppName to quit

This would expand to, for example,
tell application “Eudora 6” to quit
since thisAppName contains the string “Eudora 6”.

This does not work, yet if I directly type:
tell application “Eudora 6” to quit
then, it works.

Here is the code:

set visible of every process whose visible is true and name is not "Finder" to false

set allAppFileList to (file of every application process whose file type is "APPL")

set allCacheAppNames to ¬
	{"Eudora", "Explorer", "iPhoto", "Mozilla", "Netscape", "Safari"}	
repeat with thisAppFile in allAppFileList
	
	if thisAppFile is not (missing value as string) then
		
		set thisAppInfo to info for thisAppFile
		set thisAppName to name of thisAppInfo
		
		repeat with eachCacheAppName in allCacheAppNames
			
			if (thisAppName contains eachCacheAppName) then
				
				-- for example, Eudora 6.app
				-- strip ".app" suffix
				set offset_dotapp to (offset of ".app" in thisAppName)
				if offset_dotapp > 0 then set thisAppName to ¬
					(text 1 thru (offset_dotapp - 1)) of thisAppName
				
				-- for example, Eudora 6 -- and this does NOT work
				tell application thisAppName to quit
				
			end if
			
		end repeat -- repeat with eachCacheAppName in allCacheAppNames
		
	end if -- if eachAppFile is not (missing value as string) then
	
end repeat -- repeat with eachAppFile in allAppFileList

It’s not as complicated as that. When ‘telling’ an application, its path string at run time has the same effect as its name during compilation:

set allCacheAppNames to ¬
  {"Eudora", "Explorer", "iPhoto", "Mozilla", "Netscape", "Safari"}

repeat with i from 1 to (count allCacheNames)
  try
    tell application "System Events"
      set thisAppFile to (file of first application process whose name contains item i of allCacheNames)
    end tell
    tell application (thisAppFile as string) to quit
  end try
end repeat

If you may have more than one version of any app open:

set allCacheAppNames to ¬
  {"Eudora", "Explorer", "iPhoto", "Mozilla", "Netscape", "Safari"}

repeat with i from 1 to (count allCacheNames)
  try
    tell application "System Events"
      set theseAppFiles to (file of every application process whose name contains item i of allCacheNames)
    end tell
    repeat with thisAppFile in theseAppFiles
      tell application (thisAppFile as string) to quit
    end repeat
  end try
end repeat

Sorry. I miscopied one of the variable names.

set allCacheAppNames to ¬
  {"Eudora", "Explorer", "iPhoto", "Mozilla", "Netscape", "Safari"}

repeat with i from 1 to (count allCacheAppNames)
  try
    tell application "System Events"
      set thisAppFile to (file of first application process whose name contains item i of allCacheNames)
    end tell
    tell application (thisAppFile as string) to quit
  end try
end repeat

And:

set allCacheAppNames to ¬
  {"Eudora", "Explorer", "iPhoto", "Mozilla", "Netscape", "Safari"}

repeat with i from 1 to (count allCacheAppNames)
  try
    tell application "System Events"
      set theseAppFiles to (file of every application process whose name contains item i of allCacheNames)
    end tell
    repeat with thisAppFile in theseAppFiles
      tell application (thisAppFile as string) to quit
    end repeat
  end try
end repeat

I typed in your code as follows:

repeat with i from 1 to (count allCacheAppNames)
	try
		tell application "System Events"
			set thisAppFile to ¬
				(file of first application process ¬
					whose name contains item i of allCacheAppNames)
		end tell
		
		tell application (thisAppFile as string) to quit
	end try
end repeat

=====

but Eudora, for example, remained open after script completion.

I still missed one of the miscopied variable names didn’t I?. Thanks for correcting it.

But do you mean “Eudora, for example, remained open” or “Eudora (only) remained open”? The script definitely works on my 10.2.8 machine, quitting every app I’ve named, or partially named, in the list - including Explorer and Safari - regardless of whether that app’s file is a file or a bundle. I don’t have Eudora, though, so I’m not able to test with it.

I suppose the next thing to try is to comment out the ‘try’ and ‘end try’ lines to see if trying to quit Eudora is throwing an error, and if so, what.

Hi,

What if you just use the process names. This usually works for me unless you’re trying to quit some background application whose process has a different name.

set allCacheAppNames to ¬
{“Eudora”, “Explorer”, “iPhoto”, “Mozilla”, “Netscape”, “cSafari”}

tell application “System Events”
set visible of every process to true
set proc_names to (name of every process whose visible is true)
end tell
repeat with this_proc_name in proc_names
repeat with this_name in allCacheAppNames
if this_proc_name contains this_name then
tell application this_proc_name to quit
exit repeat
end if
end repeat
end repeat

I forgot that I changed Safari’s name because I’m using it right now.

gl,

  1. Eudora, Safari, iPhoto – all of them still remain open.

  2. Error that is thrown is similar to “Can’t get application ‘Eudora 6’”, with or without tell application “System Events” envelope, with or without try-end try envelope.

  3. Just to keep it simple, changed line:
    set allCacheAppNames to {“Eudora”}

  4. By the way, I have 10.3.3 Panther

… and really important, thanks bunches for all your joint patience.

Hi John,

This should work fine for you:


set all_cache_app_names to {"Eudora", "Internet Explorer", "iPhoto", "Mozilla", "Netscape", "Safari"}

repeat with one_app in all_cache_app_names
	
	try
		tell application "Finder" to set one_app to name of process (one_app as text)
		tell application one_app to quit
	end try
	
end repeat

The first line of the loop is just to test to see if we can do this. If we can’t, the process isn’t running and AppleScript will throw an exception (thus taking us out of the ‘try’ block and on to the next process name). If we can do the first line, we’ll stay in the try block and tell the process to quit.

-Colin Foster
(author of Quit Anything and guy who has spent FAR too much time figuring out how to systematically quit processes. :slight_smile: )

Hmmm. It’s correctly identifying the process name. Maybe there’s a reference resolution problem in 10.3.3. If you’ve had no luck with anyone else’s suggestions, does this overkill make any difference?

set allCacheAppNames to {"Eudora", "Explorer", "iPhoto", "Mozilla", "Netscape", "Safari"}

repeat with i from 1 to (count allCacheAppNames)
  set partialName to item i of allCacheAppNames
  tell application "System Events"
    set thisAppProcess to (first application process whose name contains partialName)
    set thisAppName to (name of thisAppProcess) as string
  end tell
  tell application thisAppName to quit
end repeat

Or, without the two o’clock in the morning effect… :oops:

set allCacheAppNames to {"Eudora", "Explorer", "iPhoto", "Mozilla", "Netscape", "Safari"}

repeat with i from 1 to (count allCacheAppNames)
  set partialName to item i of allCacheAppNames
  try
    tell application "System Events"
      set thisAppProcess to (first application process whose name contains partialName)
      set thisAppName to (name of thisAppProcess) as string
    end tell
    tell application thisAppName to quit
  end try
end repeat

Unfortunately, neither Colin’s nor Nigel’s approach worked.

Trying to recap a bit,

the following does not work with the error ‘Can’t get application “Eudora 6”’
set thisAppName to “Eudora 6”
tell application thisAppName to quit

However,
tell application “Eudora 6” to quit
does work

=====

Next …

repeat with i from 1 to (count allCacheAppNames)
	try
		tell application "System Events"
			set thisAppFile to ¬
				(file of first application process ¬
					whose name contains item i of allCacheAppNames)
		end tell
		
		display dialog thisAppFile as string
		
		tell application (thisAppFile as string) to quit
	end try
end repeat

displays the directory string followed by Eudora 6, with no script errors, but Eudora remains open.

=====

Next,

tell application "System Events"
set allAppFileList to ¬
	(file of every application process ¬
		whose file type is "APPL")
      end tell

repeat with thisAppFile in allAppFileList
			
	repeat with eachCacheAppName in allCacheAppNames
		
		set thisAppName to name of thisAppFile
		
		if (thisAppName contains eachCacheAppName) then
			
			-- for example, Eudora 6.app
			display dialog thisAppName
			
			-- strip ".app" suffix
			set offset_dotapp to (offset of ".app" in thisAppName)
			if offset_dotapp > 0 then set thisAppName to ¬
				(text 1 thru (offset_dotapp - 1)) of thisAppName
			
			-- for example, Eudora 6
			display dialog thisAppName
			
			tell application (thisAppName as string) to quit
			
		end if
		
	end repeat -- repeat with eachCacheAppName in allCacheAppNames
	
end repeat -- repeat with eachAppFile in allAppFileList

This also does not work with the error “Can’t get application ‘Eudora 6’”

Even if I put the tell application statement before the stripping of “.app”, the error reads “Can’t get application ‘Eudora 6.app’”

By the way, the above results are ditto even without the tell application “System Events” envelope at the top.

I really remember my being very happy with OS 9 scripting … lots of additions out there made my life very easy.

Aarrgh!

Hi,

What if you use the path to the bundle instead. See if this quits Eudora:

set the_app to choose file
tell application “Finder”
set ct to creator type of the_app
set app_path to (application file id ct) as string
end tell
tell application app_path to quit
–“CSOm”

I’m not sure if “CSOm” is the creator type for Eudora so used the choose file here.

gl,

or use the ‘application file’ property of application process:

tell application “Finder”
set the_app to item 1 of (every process whose name contains “eudora”)
set app_path to (application file of the_app) as string
end tell
tell application app_path to quit

When I use your ‘file of …’ method, I get the path to the application inside the bundle. Not sure what you get with Eudora but maybe you should check it out.

gl,

Oh dear. And you say this is true with other applications as well? It doesn’t make sense that the name should be acceptable when the script’s compiled but not when it’s run.

OK. Three last-ditch guesses at what might work, then I’m out of ideas…

-- Resolve 'application thisAppName' before telling it anything
set thisAppName to "Eudora 6"
tell (get application thisAppName) to quit

-- Ditto, with overkill
set thisAppName to "Eudora 6"
set thisApp to application thisAppName
tell thisApp to quit

-- Compile and run the quit line
set thisAppName to "Eudora 6"
run script ("tell application " & thisAppName & "" to quit")

Oh yes. And of course:

set thisAppName to "Eudora 6"
if thisAppName is "Eudora 6" then tell application "Eudora 6" to quit

Seconded. :wink:

I just downloaded and installed Eudora 6.1, which installs as just “Eudora” and changed its name to match what you must have: “Eudora 6”.

The problem is, it shows up in the Dock as “Eudora 6,” but its name is really just “Eudora.”

I launched Eudora 6, and also a (renamed) copy of TextEdit 13 and then ran the following script:


set all_cache_app_names to {"Eudora", "TextEdit"}

repeat with one_app in all_cache_app_names
   
   try
      tell application "Finder" to set one_app to name of process (one_app as text)
      tell application one_app to quit
   end try
   
end repeat 

and both quit just fine. But if I used the names “Eudora 6” and “TextEdit 13” in the script (which is what the Dock tells me their names are) then the script fails to quit those processes.

So perhaps this is just a naming problem. Maybe you could try to run the following code once to get the real names of the apps you are having trouble quitting (while they are running of course). Then use the real name of the process in your list.


tell application "Finder"
	name of every process
end tell

(Plug: Or Quit Anything will also display the real name – it’s free: http://frozenheads.com/quit_anything )

I guess another solution to this problem would just be to inline your quit statements instead of using a loop (since you mentioned it still worked when you used a constant instead of a variable):


	try
		tell application "Eudora 6" to quit
	end try
	try
		tell application "Safari" to quit
	end try
	-- and so on

-Colin.

A slightly different approach… (works on 8.6)… substitute the appropriate creator types… (file id’s). It does not allow for the possibility of multiple app versions using the same creator.

tell application “Finder”
set app_names to {name of application file id “MSIE”, name of application file id “MOSS”}
set process_names to the name of every process whose file type is “APPL”
end tell
try
repeat with this_app in app_names
if this_app is in process_names then
tell application this_app
quit
end tell
end if
end repeat
on error
end try

(EDIT - After trying this on X, I conclude it won’t work… sorry.)


You can use the run script command from the Standard Additions to compile and run an AppleScript script on the fly.

on quitOthers(keepOpen)
	tell application "System Events"
		get application processes
	end tell
	repeat with myApp in result
		set AppName to name of myApp
		if AppName is not in keepOpen and AppName is not in systemProcesses then

			run script "
try
	tell application "" & AppName & "" to quit
end try"

		end if
	end repeat
end quitOthers

I used this to quit other applications in this script used to log out after the current song in iTunes finishes.

property maxWait : 10
property systemProcesses : {"loginwindow", "Dock", "SystemUIServer", "System Events"}
quitOthers({"iTunes"})
HideApp("iTunes")
endOfSong()
tell application "loginwindow"
	ignoring application responses
		«event aevtrlgo»
	end ignoring
end tell
on endOfSong()
	tell application "iTunes"
		set myTrack to current track
		set myFinish to finish of myTrack
		set timeLeft to myFinish - player position
		repeat while timeLeft > 0 and myTrack = current track
			if timeLeft > maxWait then
				delay maxWait
			else
				delay timeLeft
			end if
			set timeLeft to myFinish - player position
		end repeat
	end tell
end endOfSong
on quitOthers(keepOpen)
	tell application "System Events"
		get application processes
	end tell
	repeat with myApp in result
		set AppName to name of myApp
		if AppName is not in keepOpen and AppName is not in systemProcesses then
			run script "try
		tell application "" & AppName & "" to quit
		end try"
		end if
	end repeat
end quitOthers
on HideApp(AppName)
	tell application "System Events"
		repeat with myProcess in processes
			if (name of myProcess = AppName) then
				set visible of myProcess to false
				exit repeat
			end if
		end repeat
	end tell
	return
end HideApp

Thank you, thank you, thank you to all, especially the last individual who used run script “…”

– Empty All Cache = Delete contents of all Cache folders

tell application “Finder”

activate
	
set visible of every process whose visible is true and name is not "Finder" to false

-- then, quit all apps that use Cache so that the Cache Folders can be emptied

set allCacheAppNames to {"Eudora", "Explorer", "iPhoto", "Mozilla", "Netscape", "Safari"}

set allProcesses to application processes

repeat with i from 1 to (count of allProcesses)
	set thisProcess to item i of allProcesses
	set processName to name of thisProcess
	
	repeat with eachCacheAppName in allCacheAppNames
		if (processName contains eachCacheAppName) then
			
			-- tell application processName to quit -- NO! for Panther???
			
			run script "

try
tell application “” & processName & “” to quit
end try
"
exit repeat
end if
end repeat

end repeat

end tell – Finder