Global variable "not defined" - applescript

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.

Related

Applescript - remember state between executions?

Some Applescripts I have used have remembered state between executions, e.g., location for Open/Save dialogues.
Now I have written an AS that takes a string as input from the user (via a display dialog). I would like the script to remember that string between executions. Possible? How?
If you make the string a property, it will remember that string between executions, until the next time you open up and re-save the script.
Here’s an example:
property myName : ""
if myName is "" then
display dialog "What is your name?" default answer ""
set myName to the text returned of the result
end if
display notification "Hello, " & myName
Save the script as an “Application”, “Script”, or “Script bundle”. If saved as “Text” (or if run from Script Editor) it will not maintain properties between runs.
The first time you run it, it will notice that myName is the empty string and request your name.
Subsequent times you run it, it will already have your name in the property myName.
If you open the script again, and then resave the script, this resets all properties. If you need the script to retain data through edits, you’ll need to save it in a database, which could be as simple as a text file in a central location.
set nameFile to POSIX file "/Users/USERNAME/name.txt"
tell application "Finder"
if exists nameFile then
set nameFileHandle to open for access nameFile
set myName to read nameFileHandle
close access nameFileHandle
else
display dialog "What is your name?" default answer ""
set myName to the text returned of the result
set nameFileHandle to open for access nameFile with write permission
write myName to nameFileHandle
close access nameFileHandle
end if
end tell
display notification "Hello, " & myName
In this case the variable nameFile doesn’t need to be a property since it never changes. Because it doesn’t need to be a property, this version also does not need to be saved as non-Text, and can even be run from Script Editor.
It is also very simple; if you need to store and retrieve multiple items, you would need to follow up on the “File Read/Write” section of “StandardAdditions”. You can get there from Script Editor under “File:Open Dictionary…”.
For more complex memory, you may find the “Property List Suite” in the “System Events” dictionary useful.

How to properly pass nested lists from Applescript to Bash

I'm working on a project that involves using Applescript to make a list of open URLs within the users Google Chrome Browser, in order to save them for when I eventually want to re-open Chrome. Finding that I needed to have a way to determine which tabs were present in which windows, I decided to try and make a nested list in Applescript, in which each window is it's own sublist of tab URLs, and then return it in the variable declared before the subshell.
The way I'm doing this is via the following code
tabs=$(/usr/bin/osascript << EOT
tell application "Google Chrome"
# save a variable to the number of windows open
set windowCount to number of windows
set myWindows to {}
repeat with x from 1 to windowCount
# count the tabs in the window we are iterated upon
set tabcount to number of tabs in window x
# this list will hold the URLs, delimited by commas
set myURLs to {}
# secondary loop, this time iterating tabs
repeat with y from 1 to tabcount
# grab URL from current tab
set tabURL to URL of tab y of window x
# append URL to end of list
copy tabURL to the end of myURLs
end repeat
# this means our end result will be a list of lists
# containing the URLs of all the tabs of all the windows
copy myURLs to the end of myWindows
end repeat
return myWindows
end tell
EOT)
The issue I'm running into is that, although Applescript is building the nested list properly, i.e.
{{"https://stackoverflow.com/questions/ask"}, {"https://twitter.com", "https://facebook.com"}}
Bash seems to flatten the list when I reference $tabs later into something like
https://stackoverflow.com/questions/ask, https://twitter.com, https://facebook.com
which leads me to believe Applescript and Bash aren't getting along when passing complex variables. Is this the case and is Bash not able to read multi-dimensional lists from Applescript? Or am I simply programming this incorrectly?
Thank you!
Here's a basic, barebones script that contains two handlers: storeURLs() and restoreURLs().
storeURLs() retrieves a nested list of currently-open Chrome tabs (grouped by window) and writes their URLs out to file. restoreURLs() reads this file and opens the URLs in Chrome, restoring the arrangement of tabs and windows.
Running the script in its current form will store the list of URLs in the file ~/.chrometabs. To get the script to restore the saved URLs, comment out the first occurrence of "storeURLs()" (line 6) by prepending it with two hyphens (--) or a hash (#); and uncomment the line below that, by deleting the two hyphens before "restoreURLs()".
property home : system attribute "HOME"
property file : home & "/.chrometabs" --> /Users/%YOU%/.chrometabs
on run
storeURLs()
--restoreURLs()
end run
on storeURLs()
close access (open for access my file)
tell application id "com.google.chrome" to set ¬
URLs to the URL of every tab in every window
write the URLs to my file
return the URLs
end storeURLs
to restoreURLs()
close access (open for access my file)
if (get eof of my file) = 0 then return false
set URLs to read my file as list
tell application id "com.google.chrome"
repeat with URLgroup in the reverse of URLs
tell (make new window)
set the active tab's URL to the URLgroup's 1st item
repeat with |URL| in the rest of the URLgroup
make new tab with properties {URL:|URL|}
end repeat
end tell
end repeat
activate
end tell
return the URLs
end restoreURLs
The script doesn't contain anything more than the most basic error-prevention, and as such, will benefit from additional error-handling. It was written and tested using AppleScript version 2.5 in macOS 10.12.6. The only potential problem I anticipate in more recent versions of macOS (Mojave, Catalina) would be security bollocks that could prevent the script creating and/or writing to the file path ~/.chrometabs, either due to its location, or due to the leading "." in the file name which denotes an invisible file in macOS.

Error in workflow when launched from calendar event

I am making a calendar alarm workflow that pulls text from a website and compares it to the text stored in a local file once a day. I store the text in the two variables "newText" and "oldText" in Automator. With the following apple-script code I try to access and compare these two variables. If they are equal, I want the break out of the workflow.
on run {input, parameters}
set newText to value of variable "newText" of front workflow
set oldText to value of variable "oldText" of front workflow
if newText is equal to oldText then
tell me to quit
end if
end run
The workflow works fine when run from automator, but when launched from the calendar-event I get the following error (second line):
Syntax Error, Expected end of line, etc. but found “"”.
All suggestions appreciated!
Outside of Automator you must wrap the related code in an application tell block
tell application "Automator"
set newText to value of variable "newText" of front workflow
set oldText to value of variable "oldText" of front workflow
end tell
if newText is equal to oldText then
tell me to quit
end if

Pass any .txt file to existing AppleScript using Automator

I currently have an AppleScript that reads a hardcoded plain text file, which contains a long list, into a variable, which is then read into another variable as paragraphs. The script works very well for my purposes. This is basically what I am using:
set fileHandler to (read POSIX file "/path/to/my/file.txt")
set newList to paragraphs of fileHandler
repeat with i in newList
# do stuff
end repeat
The omitted script opens a Safari location, invokes JavaScript using i as a variable on that page, writes the result to a new plain text file, closes the Safari window, then repeats. It continues until it reaches the end of the list, then outside the repeat runs a do shell script that cleans up the new text file a bit.
The trouble is that every time I want to run the script using a different list, I have to open the hardcoded file and paste in the list. I'd rather just drop any .txt file on to an Automator application that wraps around my current script.
I've tried to use "Combine Text Files" and I feel like I get pretty close but I can't quite pass in the contents of the .txt file the way I'd like. I can't pass it in the same, unless I am doing something wrong with it. And "Get Value of Variable"/"Set Value of Variable" add on an extra "Text" item to my list, which I don't understand.
Ideally, I'd like to do something like this:
set fileHandler to (read POSIX file arg) -- the dropped text file
set newList to paragraphs of fileHandler
repeat with i in newList
# do stuff
end repeat
...but it doesn't work that way, unfortunately.
I'd really rather not reinvent a whole new script if I can help it. Any suggestions would be great. Thanks.
Automator is actually not needed. Save this code in Script Editor as application (bundle) and drop files onto it.
on open theFiles
repeat with aFile in theFiles
set newList to paragraphs of (read aFile)
repeat with i in newList
# do stuff
end repeat
end repeat
end open

"current record" doesn't work: applescripting Filemaker Pro 13 in a loop

I have an filemaker Pro 13 database with around 120 records (it's for a conference). I want to team it up with BBEdit to create individual files for each abstract, thus applescript. Much to my surprise (and despite a lot of web tips on scripting) '[tag:current record]' is not recognised in the script.
The relevant bit is this:
FM Script:
Loop
Perform Applescript
tell application "FileMaker Pro"
activate
set MyFileName to cell "WebAbstractFileName" of table "SelectionProcess"
set MyWebAbstract to cell "WebAbstract" of table "SelectionProcess" as text
end tell
-- (BBEdit bit, which works fine in testing)
Go to Next Record (exit after last)
End Loop
This works fine if I only want to retrieve the first record!
This applescript is set within a filemaker script which loops through the records but the script doesn't care which record it's in.
I've tried adding 'of current record' before the table reference but it then gives me errors (eg error "FileMaker Pro got an error: Object not found." number -1728 from cell "WebAbstractFileName" of current record of table "SelectionProcess") Without 'current record' it works fine, but only gives me the first record.
Here's (roughly) how you could do this in a Filemaker script:
Go to Layout [ “YourTable” ]
# FIND THE RECORDS OF INTEREST
Perform Find [ Restore ]
Go to Record/Request/Page [ First ]
Loop
New Window [ ]
# ISOLATE THE CURRENT RECORD
Show All Records
Omit Record
Show Omitted Only
Set Variable [ $path; Value:Get ( DocumentsPath ) & "someFolder/" & YourTable::Somefield & ".html" ]
Export Records [ No dialog; “$path” ]
Close Window [ Current Window ]
Go to Record/Request/Page [ Next; Exit after last ]
End Loop
This will export every record in the found set as an individual file into the folder "someFolder" located in the user's Documents folder, using the contents of the YourTable::Somefield field as the filename.
If, as you say, you don't need the separate files, then of course this can be much simpler.
More tinkering solved this. The crucial bit was to change the syntax. The script now reads:
tell application "FileMaker Pro"
activate
tell current record to set MyFileName to cell "WebAbstractFileName"
tell current record to set MyWebAbstract to cell "WebAbstract"
end tell
What seems to happen is that the fields must be visible (yet I had that not be a problem at one point...go figure. If they're visible, you can drop the table specification). This script, wrapped in a Loop block, will act on the found set and (if instructed) exit after the last record.
I append the bbedit script to create a new file and save it with a variable taken from another field in case it's of interest.
tell application "BBEdit"
set notesPath to ":Users:ophiochos:Dropbox:TL Conference Admin:Webpage materials:Abstracts:"
set newFilePath to notesPath & MyFileName & ".html"
set newDoc to make new text document with properties {contents:MyWebAbstract}
tell newDoc
set source language to "HTML"
save to newFilePath
close window
end tell
end tell
Or you could simply create a calculated field that contains the contents of the desired export file for each record, loop through the records one by one, and just use an Export Field Contents ['YourCalculatedField_c'] script step.
You can also use FM to preview the html output by using a web viewer to display your html. This, along with exporting individually, you can get all this functionality without the need for an external program.
If you need to change the text encoding for output files, you can also specify those in an xslt for outputting files:
http://filemakerhacks.com/2012/09/23/export-field-contents-as-utf-8/
Also, if performing applescript from within FileMaker, the "tell application" line is not needed since it is implied.

Resources