Applescript newbie question again :) I am trying to create a small applescript that will allow me to select multiple items from a list of currently running applications and then quit those selected apps. Something like this works but rather than having to click on each dialog it would be much easier to chose from a list.
tell application "System Events"
repeat with p in every process
if background only of p is false then
display dialog "Would you like to quit " & name of p & "?" as string
end if
end repeat
end tell
Any and all help would be greatly appreciated!
Thanks!
Try this:
tell application "System Events"
set listOfProcesses to (name of every process where background only is false)
tell me to set selectedProcesses to choose from list listOfProcesses with multiple selections allowed
end tell
--The variable `selectedProcesses` will contain the list of selected items.
repeat with processName in selectedProcesses
do shell script "Killall " & quoted form of processName
end repeat
tell application "System Events"
set processList to get the name of every process whose background only is false
set processNameList to choose from list processList with prompt "Select process to quit" with multiple selections allowed
if the result is not false then
repeat with processName in processNameList
do shell script "Killall " & quoted form of processName
end repeat
end if
end tell
you can use this script which is much simpler
tell application "Finder"
get the name of every process whose visible is true
end tell
You can try this
tell application "System Events"
set AppName to name of every process whose background only is false
choose from list AppName OK button name "Ok" cancel button name "Cancel"
end
& (name of every process whose (name is "AppName") can be added to Michele Percich's and Parag Bafna's solutions to include specific menu bar applications by name.
tell application processName to quit can be used instead of do shell script "Killall " & quoted form of processName.
tell application "System Events"
set processList to ¬
(name of every process where background only is false) & ¬
(name of every process whose ¬
(name is "AppName") or ¬
(name is "AnotherAppName"))
tell me to set selectedProcesses to choose from list processList with prompt "Select process(es) to quit:" with multiple selections allowed
end tell
if the result is not false then
repeat with processName in selectedProcesses
tell application processName to quit
end repeat
end if
I wrote this following AppleScript code a few years back. I consider it to be a “Must Have” because I use it almost every single day.
This code will generate a list of Visible and Hidden application processes, allowing multiple items to be selected to kill their processes. The first items in the list will be visible application processes (not sorted alphabetically), then an empty list item (used to separate the visible from the hidden processes), and the remaining list items will be the hidden application processes (sorted alphabetically)
use framework "Foundation"
use scripting additions
property appsToKill : missing value
property NSArray : a reference to current application's NSArray
listAllAppProcesses()
activate
set killApp to (choose from list ¬
appsToKill with title "Choose The App To Kill" with prompt ¬
"Choose The App/Apps To Kill" & linefeed & linefeed ¬
& "The Empty List Item Separates The Visible From The Hidden Applications" OK button name ¬
"OK" cancel button name "CANCEL" with multiple selections allowed)
set pidList to {}
if killApp is not false then
tell application "System Events"
repeat with i from 1 to count of killApp
set thisItem to item i of killApp
tell application process thisItem
set thePID to unix id
set end of pidList to thePID
end tell
end repeat
end tell
else
return
end if
set text item delimiters to space
do shell script ({"kill -9", pidList} as text)
on listAllAppProcesses()
tell application "System Events"
set visibleAppsToKill to name of every application process ¬
where visible is true
set invisibleAppsToKill to name of every application process ¬
where visible is false
set aList to ((NSArray's arrayWithArray:invisibleAppsToKill)'s ¬
sortedArrayUsingSelector:"caseInsensitiveCompare:") as list
set appsToKill to visibleAppsToKill & "" & aList
end tell
end listAllAppProcesses
If you want it from Terminal, you can use a simple script like this quit.rb
The following example AppleScript code is pretty straight forward and will gracefully quit the selected application(s), providing the selected application(s) is (are) in a stable state:
tell application "System Events" to ¬
set appList to the name of ¬
every process whose visible is true
set quitAppList to ¬
choose from list appList ¬
with multiple selections allowed
repeat with thisApp in quitAppList
quit application thisApp
end repeat
When I present a list to choose from, I prefer to have it in alphabetical order and to that end I use a handler to first sort the list before presenting it:
on SortList(thisList)
set indexList to {}
set sortedList to {}
set theCount to (count thisList)
repeat theCount times
set lowItem to ""
repeat with i from 1 to theCount
if i is not in the indexList then
set thisItem to item i of thisList as text
if lowItem is "" then
set lowItem to thisItem
set lowItemIndex to i
else if thisItem comes before lowItem then
set lowItem to thisItem
set lowItemIndex to i
end if
end if
end repeat
set end of sortedList to lowItem
set end of indexList to lowItemIndex
end repeat
return the sortedList
end SortList
To use this with the first block of code presented I typically add handlers at the bottom of my code and then to use it, add the following example AppleScript code between the tell application "Finder" to ¬ and set quitAppList to ¬ statements:
set appList to SortList(appList)
Note: I acquired this particular handler somewhere on the Internet too many years ago to remember and unfortunately lost who to credit it to. My apologies to whomever you are.
Related
I am writing a script to go to the NYT website on Corona, get the US data, extract numbers (total, death), and to send me a notification. I am close, but when I extract numbers and display them, they are put together (ie 700021 instead of 7000,21). My question is:
How do I extract the numbers so that they are delineated?
Here is the code:
set theURL to "https://www.nytimes.com/interactive/2020/world/coronavirus-maps.html?action=click&pgtype=Article&state=default&module=styln-coronavirus&variant=show®ion=TOP_BANNER&context=storyline_menu"
tell application "Safari" to make new document with properties {URL:theURL}
tell application "System Events"
repeat until exists (UI elements of groups of toolbar 1 of window 1 of application process "Safari" whose name = "Reload this page")
delay 0.5
end repeat
end tell
to getInputByClass(theClass, num)
tell application "Safari"
set input to do JavaScript "
document.getElementsByClassName('" & theClass & "')[" & num & "].innerText;" in document 1
end tell
return input
end getInputByClass
set myVar to getInputByClass("g-body ", 5)
on returnNumbersInString(inputString)
set s to quoted form of inputString
do shell script "sed s/[a-zA-Z\\']//g <<< " & s
set dx to the result
set numlist to {}
repeat with i from 1 to count of words in dx
set this_item to word i of dx
try
set this_item to this_item as number
set the end of numlist to this_item
end try
end repeat
return numlist
end returnNumbersInString
set theNums to returnNumbersInString(myVar) as text
display notification "COVID-19 UPDATE" subtitle theNums sound name "glass"
tell application "Safari"
close its front window
end tell
You are getting a list of numbers from the returnNumbersInString handler, but just coercing the list to text doesn't normally provide any kind of formatting. One solution would be to use text item delimiters to specify the text to use when joining the list items. For example, when converting to text for the notification you could do something like:
set tempTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to ", "
set theNums to returnNumbersInString(myVar) as text
set AppleScript's text item delimiters to tempTID
Similar to your other question I helped you with, the target data is already in a table and as such I'd use the table data to get the information as its structure layout is not likely to change where target 'g-body ' of 5 may not always be the United States.
I get my data a little different way:
set theURL to "https://www.nytimes.com/interactive/2020/world/coronavirus-maps.html?action=click&pgtype=Article&state=default&module=styln-coronavirus&variant=show®ion=TOP_BANNER&context=storyline_menu"
tell application "Safari" to make new document with properties {URL:theURL}
tell application "System Events"
repeat until exists ¬
(UI elements of groups of toolbar 1 of window 1 of ¬
application process "Safari" whose name = "Reload this page")
delay 0.5
end repeat
end tell
tell application "Safari" to tell document 1 to set CountriesTable to ¬
do JavaScript "document.getElementsByClassName('svelte-f9sygj')[0].innerText;"
tell application "Safari" to close its front window
set awkCommand to ¬
"awk '/United States/{print $3,\"Cases &\",$4,\"Deaths\"}'"
set notificationMessage to ¬
do shell script awkCommand & "<<<" & CountriesTable's quoted form
display notification notificationMessage subtitle "US COVID-19 UPDATE" sound name "glass"
NOTE: The code used to determine when the page in Safari has finished loading works in macOS Mojave and later, however, for macOS High Sierra and some earlier versions, add the words buttons of in front of UI elements ... in the repeat until exists ¬ ... code.
Note: The example AppleScript code is just that and does not contain any error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.
Writing an AppleScript to open Image Capture and click the Import All button.
tell application "Image Capture"
activate
tell application "System Events"
tell process "Image Capture"
click button "Import All" of group 1 of splitter group 1 of window 1
end tell
end tell
end tell
Image Capture opens but the script throws an error message saying it couldn't find the button "Import All".
Have followed advice on other threads on how to check the location in Accessibility Inspector and how to translate that to AppleScript instructions.
What's missing?
To get the button and group numbers, you have 2 ways: use the utility aplication provided by Apple in the developper toolkit "Accessibility Inspector" or use small scripts to find the number yourselves.
I prefer using script method. it is a bit longer sometime, but it always works. Just write a script with instruction get UI elements. Here is a small example of such script:
-- return lis of UI elements of active application and paste result in Excel
property tab : ASCII character 9
global T
-- to find last active application
tell application "System Events"
set frontmostProcess to first process where it is frontmost
set visible of frontmostProcess to false
repeat while (frontmostProcess is frontmost)
delay 0.2
end repeat
set secondFrontmost to name of first process where it is frontmost
set frontmost of frontmostProcess to true
end tell
set ActifProcess to secondFrontmost as text
tell application ActifProcess to activate -- set active the last actived application
delay 1
-- recursive loop to list all elements of active window
tell application "System Events" to tell process ActifProcess to set myWindow to front window
set T to ""
getUI(myWindow, 1)
set the clipboard to T
display dialog "Result is in clipboard. paste in Excel or text document"
on getUI(UIObjet, myLevel) -- get recursively the list of UI elements
set AppleScript's text item delimiters to {"//"}
tell application "System Events" to set UIliste to UI elements of UIObjet
repeat with oneUI in UIliste
tell application "System Events"
set UItext to ("Level=" & myLevel & tab & "Name=" & (name of oneUI) & tab & (description of oneUI) & tab & "Class=" & (class of oneUI) as string) & tab & "Title=" & (title of oneUI) as string
set UItext to (UItext & tab & "Value=" & (value of oneUI) as string) & tab
try
set UItext to (UItext & "Position=" & (position of oneUI) as text)
end try
set UItext to UItext & return
try
set NbSub to count of UI elements of oneUI
on error
set NbSub to 0
end try
set T to T & return & UItext
end tell
if NbSub > 0 then
getUI(oneUI, myLevel + 1) -- there are other sub UI elements, get them
end if
end repeat
end getUI
Copy this script in Script Editor. Make active the window/application you want to get UI elements. Make this script active and run.
The result is sometime not easy to interpret because developper of the application/window you're looking for may not have use UI element clear names or titles which describe what they are. Then you will have to look their relative position in the window.
The "import all" button is "button 3 of group 2 of splitter group 1 of window 1" for image capture version 6.6. Also, I prefer to use button number, instead of button name to make sure the script works with any language.
tell application "Image Capture"
activate
tell application "System Events"
tell process "Image Capture"
click button 3 of group 2 of group 1 of splitter group 1 of window 1
end tell
end tell
end tell
Please note that any next changes done by Apple on Image Capture will impact your script.
I wrote a simple script that finds out how many active processes are running on the machine right now, and outputs the paths of each one into an array as a string.
Here's my code (it really has no legitimate function, I'm just trying to try different things to see how applescript works):
tell application "System Events"
set activeProcess to number of process
set paths to {0}
repeat with n from 1 to activeProcess
set last item of list paths to (file of process n as string)
end repeat
end tell
And here's the error applescript editor returns when I hit run:
System Events got an error: Can’t set list {0} to "Macintosh HD:System:Library:CoreServices:loginwindow.app:".
What am I don't wrong?
Try:
tell application "System Events" to set myprocess to files of processes
or
set AppleScript's text item delimiters to linefeed
tell application "System Events" to set myprocess to paragraphs of (files of processes as text)
set AppleScript's text item delimiters to {""}
You can build a list from a repeat loop like this:
set paths to {}
tell application "System Events"
set activeProcess to processes
repeat with n from 1 to count activeProcess
set end of paths to (file of item n of activeProcess as text)
end repeat
end tell
or like this:
set paths to {}
tell application "System Events"
set activeProcess to processes
repeat with aProcess in activeProcess
set end of paths to (file of aProcess as text)
end repeat
end tell
I am trying to write an applescript script that resizes all open windows. In order to make sure that I'm getting to all the windows, I'm making my script say the name of the application as well as the number of open windows of that application.
Interestingly, while I hear the names of all my open applications, my script says that they all have 0 windows open. How can I fix this issue?
Here's my code:
tell application "System Events"
repeat with theProcess in (every process)
if background only of theProcess is false then
if name of theProcess is not "Finder" then
if name of theProcess is "Google Chrome" then
say "Chrome woo hoo"
say (count windows as string)
else
say name of theProcess as string
say (count windows as string)
tell theProcess
repeat with theWindow in windows
say "found a window of"
say (name of theProcess) as string
tell theWindow
click button 2
end tell
end repeat
end tell
end if
end if
end if
end repeat
end tell
I'm on Mac OS X 10.7.5, using automator 2.2.4 to write/run this applescript
You have to tell the process to count windows. After all it's the process that knows about its windows, not system events.
You have told the process to say its name e.g. "say name of theProcess as string" however you only use "say (count windows as string)"... no process is tied to that. Try "count windows of theProcess". Basically you have lines where sometimes you tell the process, other times you don't, and other times where you tell the process even though you've already told the process, so you do it twice. That's where you have "say (name of theProcess) as string" but that code is inside a "tell theProcess" block so it's already being told to theProcess.
Really you need to go through your code and be more precise. A tip... if you want to click a button in a window then the window must be frontmost on the screen otherwise you can't click it. Another tip... "name" is already a string so you don't need to coerce that to a string.
By the way, I agree with Michael Dautermann's comment to your post... there will be processes where you won't get access. But you'll find that out as you progress.
Here's how I would write your code. Basically I would get all of the variables at the beginning using a "tell theProcess" block. Then I can do stuff with those variables. I hope that helps. Notice that I only made the process frontmost which means if it has multiple windows open it will only click a button on the front window. You'll have to add code to make each window come to the front before you can click its button. Good luck.
tell application "System Events"
repeat with theProcess in processes
if not background only of theProcess then
tell theProcess
set processName to name
set theWindows to windows
end tell
set windowsCount to count of theWindows
if processName is "Google Chrome" then
say "Chrome woo hoo"
say windowsCount as text
else if processName is not "Finder" then
say processName
say windowsCount as text
if windowsCount is greater than 0 then
repeat with theWindow in theWindows
say "found a window of " & processName
tell theProcess
set frontmost to true
tell theWindow
click button 2
end tell
end tell
end repeat
end if
end if
end if
end repeat
end tell
I create a list of all open windows of visible applications on Mavericks like this:
tell application "System Events"
set this_info to {}
repeat with theProcess in (application processes where visible is true)
set this_info to this_info & (value of (first attribute whose name is "AXWindows") of theProcess)
end repeat
this_info -- display list in results window of AppleScript Editor
end tell
You need to allow any app using this to access the interface under Accessibility.
How would I quit all running user applications using Applescript?
It's okay... I think I found my answer:
tell application "System Events" to set the visible of every process to true
set white_list to {"Finder"}
try
tell application "Finder"
set process_list to the name of every process whose visible is true
end tell
repeat with i from 1 to (number of items in process_list)
set this_process to item i of the process_list
if this_process is not in white_list then
tell application this_process
quit
end tell
end if
end repeat
on error
tell the current application to display dialog "An error has occurred!" & return & "This script will now quit" buttons {"Quit"} default button 1 with icon 0
end try
After some googling, I found a better approach:
It uses background only to build the initial app list, rather than
visible is true. The difference is that the other scripts will fail
to quit an app that's been hidden with ⌘H.
It provides an exclusions
list so that, for example, you can prevent your script editor from
quitting each time you test the script.
Adapted from a thread on MacScripter.
-- get list of open apps
tell application "System Events"
set allApps to displayed name of (every process whose background only is false) as list
end tell
-- leave some apps open
set exclusions to {"AppleScript Editor", "Automator", "Finder", "LaunchBar"}
-- quit each app
repeat with thisApp in allApps
set thisApp to thisApp as text
if thisApp is not in exclusions then
tell application thisApp to quit
end if
end repeat
tell application "System Events" to set the visible of every process to true
set white_list to {"Finder"}
try
tell application "Finder"
set process_list to the name of every process whose visible is true
end tell
repeat with i from 1 to (number of items in process_list)
set this_process to item i of the process_list
if this_process is not in white_list then
tell application this_process
quit
end tell
end if
end repeat
on error
tell the current application to display dialog "An error has occurred!" & return & "This script will now quit" buttons {"Quit"} default button 1 with icon 0
end try
tell application "System Events" to set quitapps to name of every application process whose visible is true and name is not "Finder"
repeat with closeall in quitapps
quit application closeall
end repeat