I have made a small automator script that runs a bash shell script and gets two outputs... On viewing results it appears like this below...
I want them in two automator variables
Assume I used a script like
echo "200"
echo "19 hours, 4 minutes and 42.765 seconds"
and on viewing the results it shows this (and I want each of these as automator variables called count and duration). I want it to be sent to a display notification with subtitle as "count files processed" and message as "duration elapsed". How can I achieve this?
You can modify Automator variables by applescript. The variables must exists in the workflow, so you first should add two variables, to get something like on the next image:
You can set anyting as their initial value...
After the above, you can use the next applescript, right after your shell script
on run {input, parameters}
set value of variable "Count" of front workflow to item 1 of input
set value of variable "Duration" of front workflow to item 2 of input
return input
end run
It is not fully correct, (for example it isn't check the number of arguments on the input), but you get an idea.
So after the next:
Your automator variable Count will contain 200, and the variable Duration will contain the text.
Related
PreNote: I am open and hungry for any information, advice, tip etc.
Hello Everyone!
I am trying to create automation with applescript. This is my first personal applescript task but I have some valuable questions. Basically I am trying to catch live notifications from a website and display them in mac os notification.
I am trying to build process for a few days but I don't want to give a mess to you :) so I have roughly explained my process below.
(* Variables used in whole process
set $webToCheck > This is Safari webpage which I want to run my script on it. It won't be front window, script should be run with its name or other property.
set $theClass > This is class name of DOM element to check if it is exist or not. This class is not always exist on DOM of $webpage. It comes with notifications so when use it in "do Javascript" I got error "variable is not defined"
set $num > number of class to use in "do Javascript"
set $input > variable to assign HTML text
set $modifiedInput > Text of input seperated from HTML tags
*)
-- Step 1
tell application "Safari"
work on $webToCheck
-- Step 2
repeat until $input is not empty
set input do Javascript
document.getElementsByClassName > $theClass, $num of $webToCheck
end repeat
-- Step 3
modify text of $input to seperate from RAW HTML -- For example: <a class="" value=""> TEXT to be seperated </a>
Display notification $modifiedInput
-- Step 4
Go back to step 1 or 2 to check and display notification again
First of all, here are some general tips though:
Applescript won't accept $ at the start of variable names.
The variable assignment you are looking for is set {variable} to {value}. You can optionally at the end of it clarify the variable's class using as {class} at the end of the assignment.
Focusing a certain website does not happen with work on {URL} but as with most object oriented things in Applescript with the tell-statement. It will be shown in the full solution.
Text concatenation in Applescript happens with &. So something like "Hello " & "World" is the standard way to do it.
Modification of most things in Applescript happens with set.
It is easier to use innerText instead of innerHTML as splitting text in Applescript is a bit of a pain.
There is no goto but you could wrap the first few steps into a function, which are declared with on or to in Applescript.
Here is the full code with some documentation sprinkled in there:
global webToCheck, theClass, num, input --This says that all variables can be used even in functions.
set webToCheck to "youtube.com" --Strings can only use double quotes.
set theClass to "style-scope yt-alert-with-actions-renderer" --I will use an actual demo to prove that it is working
set num to 0 as integer -- This is the type declaration I was talking about. For numbers we have integer, real(float) and number.
set input to "" -- You don't have define everything at the top, but I will do so for this.
on displayNotification()
tell application "Safari"
tell window 1 -- This will target only the first window. For multiple windows you would have to write a repeat with-loop(for-loop), which I'm not going to do, for the sake of simplicity.
tell (first tab whose URL contains webToCheck) -- This targets just the first tab which contains the webToCheck variable.
set input to do JavaScript "document.getElementsByClassName('" & theClass & "')[" & num & "].innerText" -- This is the way I would go about writing the Javascript. I think you had something different in mind, but this works for my example.
display notification (paragraph 1 of input) with title webToCheck -- This displays the first line of my input since that is the relevant part. I also set a title so I doesn't just say "Script Editor"
end tell
end tell
end tell
end displayNotification
repeat 4 times -- I think this is quite obvious. Adjust this to your needs.
displayNotification()
delay 4
end repeat
Running this while having not used youtube on Safari in a while it displays this:
Note that this isn't the most elegant solution, but I think it is readable and it (hopefully) works for your needs.
In my Automator action, I use an "Run AppleScript" action, that returns a list (via AppleScript). Here is the AppleScript:
on run {input, parameters}
set result to {"Foo", "Bar", "42"}
return result
end run
Later in my Automator action, I need to use values "Foo", "Bar", and "42" in different places.
How can I assign those 3 values to different Automator variables?
Taking your question literally, you have to first set the result of the Run AppleScript action, which in this case is a list, to a Set Value of Variable action.
Next, you'd add a Get Value of Variable1 action. setting its Options to [√] Ignore this actions input so as to make a disconnect from the Set Value of Variable action.
Next, add a Run AppleScript action with the following example AppleScript code:
on run {input, parameters}
return item 1 of input
end run
Then add a Set Value of Variable action for this first item in the list returned from to original Run AppleScript action.
Repeat again for the next two items in the list.
1Technically you could send the output of the first Set Value of Variable action directly to the second Run AppleScript action to set the first list item to it new variable; however, I broke it into a separate action so the creation of the three list items as separate variables followed the same action path.
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.
My AppleScript examines an image file and outputs some of that information. I need this information as normal output (stdout) of the script for further processing (in an InDesign script). But as soon as I open an image file in my AppleScript, the global variable which is meant to hold the result, gets lost.
This is fine (but useless):
global result
set result to "initialised"
set imgfile to POSIX file "/Users/hell/Pictures/interesting_stuff.jpg" as alias
tell application "Image Events"
-- start the Image Events application
launch
set result to "new text"
end tell
return quoted form of result
The following script is what I want, but throws the error "The variable 'result' is not defined (-2753)"
global result
set result to "initialised"
set imgfile to POSIX file "/Users/me/Pictures/interesting_stuff.jpg" as alias
tell application "Image Events"
-- start the Image Events application
launch
-- open image file
set img to open imgfile
-- here would go some commands about img instead of "new text"
set result to "new text"
-- close image file
close img
end tell
return quoted form of result
What is the problem here and how can I get the result out of my script?
result is a special identifier in AppleScript, which you may notice in Script Editor is printed in a different colour/font/style to other variable names you use. It's an AppleScript property that always contains the value returned by the command that is executed immediately before it.
The solution is most likely to choose a different word other than result for your identifier.
As your script stands, you also don't need to declare the variable as a global, since there are no scoping issues in your script that require access to variables outside of its block, which becomes a consideration when creating handlers or script objects.
Is there a way to retrieve result of an Automator app script in an external Applescript app (not the Applescript lines in Automator)?
Something like:
tell application "My_Automator_App"
-- suppose My_Automator_App checks the Calendar to see if there some events today
-- "Show Result" in Automator will display a list
get the_Result -- list returned by Automator
end tell
I looked into this a little bit and didn't find a natural means by which AppleScript and Automator applets can communicate, although this doesn't mean one definitely doesn't exist.
In the meantime, you could implement one of a couple of workarounds/hacks that, although a little unseemly in their methods, do achieve the desired result without creating any side issues that would affect the functionality of an applet itself.
1. Use The Clipboard
Append a Copy to Clipboard action at the end of the applet's workflow, or following the action whose result you would wish to be reported.
Retrieving the clipboard from AppleScript is simple:
get the clipboard
This will probably suit return values that are simple text strings or a number. Passing an array of items from an Automator action to the clipboard isn't very reliable, sometimes only allowing access to the first item. However, this can be resolved with a small AppleScript within the workflow to process results arrays properly and convert them into an accessible format, e.g. a comma-delimited string.
However, the clipboard is also capable of storing image data, file references, and other data types, so it will be possible (if not always straightforward) to send those to be retrieved in an AppleScript.
Where possible, strings and numbers are the safest storage types.
2. Write Out To A Temporary File
To avoid using the clipboard as an intermediary, or if you wish the applet to report multiple variables without too much work, then writing the data to a temporary file is a fairly common practice, such as is done in shell scripts when persistant values are needed between multiple executions of the same script.
There's actually a special directory that gets periodically purged so that temporary data files don't accumulate: /tmp. It's hidden in Finder, but you can still create files and delete them as you would any other directory. Files that aren't access for 3 days get purged by the system.
There is a New Text File action that can write text to a file:
Specifying the /tmp directory is most easily done by creating a variable whose value is "/tmp" (without the quotes), and dragging that variable onto the appropriate field.
But my inclination would be to insert an AppleScript, or more suitably, a shell script into the workflow, with which file manipulation becomes easy and more capable.
Calendar Events Example
Using a similar example to the scenario you described, a simple applet that retrieves calendar events might have a workflow that looks like this:
where you can calibrate the first action to isolate the events you want, such as today's events. That action returns a type of object that isn't easily processed by AppleScript, but the second action extracts the relevant data in text format, summarising the list of events that the first action returned.
This is where a temporary file is useful to write out the data to a text file, which can then be retrieved in an AppleScript.
Given this Automator applet saved under the named "CalEvents", this AppleScript makes use of that applet and its result:
property tidEvents : [linefeed, linefeed, "EVENT", space] as text
property tidDetails : {tab, " to "}
property tid : a reference to my text item delimiters
run application id "com.apple.automator.CalEvents"
set tid's contents to tidEvents
set EventsSummary to read POSIX file "/tmp/EventsSummary.txt"
set EventsList to the EventsSummary's text items
set [[n], EventsList] to [it, rest] of EventsList
set n to n's last word as number
EventsList -- The final list of events from first to last
Upon its first run, the applet requires consent to access your calendar information, which only needs to be done once and will make the above script appear to fail. Once authorised, you can run the script as often as you like to get the most up-to-date content of the /tmp/EventsSummary.txt file.
Each item in the list variable EventsList is a block of text that looks like this (asterisks are my redactions for privacy, as are the address items in curly braces):
4 OF 8
Summary: GP Appointment
Status: none
Date: 07/12/2017 to 07/12/2017
Time: 14:45:00 to 15:45:00
Location: ******** Medical Centre
{Address Line 1}
{Address Line 2}
{County}
{Post Code}
United Kingdom
Notes: 01*** *****9
Each value is separated from the preceding colon by a tab character, which won't be obvious here. Also, as you can tell from the date format and address, these are British-formatted values, but yours will, of course, be whatever they are set as in Calendar.
But since each list item is much the same, extracting details for a particular event will be simple in AppleScript, first by splitting a particular event item into paragraphs, and then splitting a particular paragraph by either a tab or space character (or both) or some preposition that naturally delimits useful bits of text:
set |Event| to some item in the EventsList
set tid's contents to tidDetails
set EventDetails to {title:text item 2 of paragraph 2 ¬
, startTime:text item 2 of paragraph 5 ¬
, EndTime:text item 3 of paragraph 5} of the |Event|
which places the important event details, such as its name and start/end times, in an AppleScript record:
{title:"GP Appointment", startTime:"15:45:00", EndTime:"16:00:00"}
I'm trying to do the simplest thing in the world - a basic iterator in Automator. The workflow goes:
Get Value of a Variable (initially set to 1)
Run Applescript:
on run {input, parameters}
set input to input + 1
return input
end run
Set Value of a Variable
Loop
It works the first time, moving from 1 up to 2 as expected. But it fails on the second pass, giving the error
Can't make {} into type number. (-1700)
I'm clueless as to why - I've tried getting it to output from the Applescript as an integer and it makes no difference. Can anyone shed some light?
Your error is because on the second loop of your workflow your applescript is not receiving any input. I would guess that your loop function is not receiving any input and therefore it is not passing anything back into the applescript. Whatever is between your applescript and the loop function must be interfering somehow.
As an alternative, try this as your applescript. Your automator workflow should only have 2 actions, this applescript code and the loop action set to "use current results...".
In this code, on the first loop there won't be any input to the applescript so it will ask you for input, and then on subsequent loops the applescript will receive input from the loop action and thus it will increment your initial input.
Good luck.
on run {input, parameters}
if input is {} then
display dialog "Enter a number" default answer "1"
set input to (text returned of result) as number
else
set input to input + 1
end if
return input
end run