Here is the thing:
I'm using AppleScript in Automator to get the clipboard value, and of course it works, but when I want to get multiple separated value, it always returns me only one value on the top。
Here is the step:
In Automator, import multiple "Get Value of Variable" actions, and
in these actions, I will set multiple values, all of these values
are e-mail format
Import an action named “Ask For Confirmation”, without this action,
I can’t pass multiple values to the next action “Choose from list”(I
don’t know why, but it works)
Import an action named “Choose from list” to let users choose the
e-mail values I’ve pre-set in this Automator application
Import another action named “Set Value of Variable” to get the
values users have chosen
Import an action named ”Copy to Clipboard” to copy these values to
clipboard
Import an action named “Run AppleScript” and here is my code:
on run {input, parameters}
--get the clipboard info
set Storage to get the clipboard
display dialog Storage
return input
end run
I've tried to copy some text_1, text_2 ... manually(command+c, command+v) and then run my AppleScript only, and it turns out the result what I really want like this:
Here is my Script Editor code:
I have to say, due to some limitation I can only use Automator and AppleScript,so is there any solution or suggestion?
Here is the "Get Value of Variable" picture
Get Value of Variable
Possible Explanation:
I believe this is a bug in either the Automator Copy To Clipbard action or AppleScript. Automator actions are often written in Objective-C, and it has some data types that AppleScript doesn't. It looks like the Automator action copies an array to the clipboard, which is something you can do with Objective-C, but not with AppleScript.
My feeling is that AppleScript is the entity at fault here, as the action is doing what it is meant to, and within the Automator context, it wouldn't pose a problem keeping the clipboard's data as an array type. AppleScript likely hasn't catered for this in its implementation of clipboard data handling, and does a poor job of coercing the array or list into plain text, which—as you stated—only contains the first element of the array.
Solutions:
1. Use a do shell script command
Instead of:
set Storage to get the clipboard
try:
set Storage to do shell script "pbpaste"
2. Use AppleScriptObjC
Since the Automator action is probably written in ObjC, it's reasonable to assume that using AppleScriptObjC will give us access to the necessary data types.
Replace your entire AppleScript with this:
use framework "Foundation"
use scripting additions
set Storage to (current application's NSPasteboard's generalPasteboard's ¬
stringForType:(current application's NSPasteboardTypeString)) ¬
as text
display alert Storage
3. Access the data through the input variable
The Run AppleScript action in Automator takes the result of the previous action and stores it in the variable attached to the on run {input, parameters} handler, namely input (you can ignore parameters).
Currently, your workflow actually sends the contents of the clipboard (the output of the Copy To Clipboard action) directly to the input variable of your AppleScript.
Therefore, you can replace the entire AppleScript with this:
on run {input, parameters}
set the text item delimiters to linefeed
set Storage to the input as text
display dialog Storage
end run
Any one of these solutions should work, so just choose your preferred method. Number #3 probably makes most sense in your current set up, and is the simplest.
Related
I am struggling to call the 'folder' variable within my apple script (shown in the image).
I don't have much experience with apple script so I'm sure I'm not calling it correctly but I can't find a better example online.
Any help would be appreciated.
AppleScript
You don't need a variable action.
The result of the first action is passed to the second as a list of alias specifiers.
item 1 of input is the desired item, you just have to coerce it to POSIX path
I am creating a text file and looping through every Safari window, every tab, and pasting each link into the .txt file. However I am getting an extra missing value written to the .txt file. I know I can explicitly check for missing values but I don't understand where is the "empty" window/value?
on run {input, parameters}
(* create text file to hold links *)
tell application "Finder" to make file at desktop with properties {name:"links_0"}
set classicPath to (((path to desktop folder) as string) & "links_0")
(* get links of all windows *)
tell application "Safari"
repeat with this_window in windows
set the_URLs to ""
repeat with this_tab in tabs of this_window
set the_URLs to the_URLs & URL of this_tab & return
end repeat
do shell script "echo " & quoted form of the_URLs & " >> " & POSIX path of (classicPath)
do shell script "echo >> " & POSIX path of (classicPath)
end repeat
end tell
return input
end run
sample output (2 windows, each with 2 tabs):
https://discussions.apple.com/thread/64896
https://discussions.apple.com/thread/22543
https://discussions.apple.com/thread/25140
https://discussions.apple.com/thread/22546
missing value
An easier way to do this would be:
set my text item delimiters to linefeed
set fp to POSIX path of (path to desktop folder) & "links_0.txt"
close access (open for access fp) -- Create the file if it doesn't exist
# set eof of fp to 0 -- Erase any existing contents in the file
tell application id "com.apple.Safari" to tell every tab of every window ¬
to tell (the URL as text) & linefeed to continue write it to fp ¬
starting at eof
This currently appends URLs to the end of the file. To overwrite the file, uncomment this line:
# set eof of fp to 0
by removing the hash symbol.
Note: There's potential for confusion having read the comment left by #user3439894, where he states:
"It also shows code missing from CJK's answer in which a file should be closed after being written to. It also wraps relevant code in a try statement so if there is an error it attempts to close the file."
I would take what you read at the provided link with a pinch of salt. Sadly, a lot of the AppleScript documentation from Apple contains code that is poorly written and is part of the reason a lot of bad AppleScript persists so pervasively on the internet. Some of the documentation provided by Apple is also flat out wrong, which makes it very difficult for people to learn from and to know whose advice to take.
The code I have provided above, I assure you, is very much complete. Read on for a pretty boring explanation that I wish I didn't have to give, but now have to:
You'll see a lot of people do this:
set fh to open for access filepath with write permission
write somedata to fh
close access fh
It's not wrong, per se, but it's a pretty draconian way of using these read/write commands, which persists among many simply because they've always done it that way, and only seen it done that way. It's cumbersome and completely unnecessary1.
#user3439894 alluded to a try statement, which would, indeed, be needed for this method. open for access opens a file handle that was necessary in order to write out to a file. However, if an error in the script occurs during the write process, then the file handle is left dangling because the script terminates before being able to close access to the file. The way around this would be to use a try statement whose purpose was to catch an error, and ensure the close access command still gets executed:
try
set fh to open for access filepath with write permission
write somedata to fh
close access fh
on error
close access fh
end try
open for access and close access are redundant. There's no need to use them, and in fact, their use is only creating a potential problem that then needs a workaround in order to solve.
write--and read--are safe and advisable to use on their own, and they don't need a try block to catch potential errors. So why do the two commands I just called redundant appear in my script at all ?
close access (open for access fp)
One nifty side effect of the open for access command is that it will create a file at the specified path if one doesn't already exist. This is really useful because it negates the need to call out to System Events or (shudder) Finder to do this for you. It also has seems to have a wider scope for creating files at locations that other AppleScript applications don't have permission to access if they're sandboxed, etc.
Once open for access has created the file--or opened one that already exists--it returns a reference to the file handle. Then close access is used to immediately destroy file handle, because we don't actually have any use for it, but also don't want it left open. There's also no need for a try block: any error that could possibly arise would do so during the creation of the file handle, which would mean that the file handle won't be created, and so cannot be left open.
1The way the data gets written out now is fundamentally different to how it was written out when these commands were first introduced, and previously, write would not be able to access a file without first explicitly opening a file handle to it and declaring the need for writing permissions. Now, everything gets handled within the write command itself, including clean up.
I am using NSUserAutomatorTask to launch an Automator workflow from a macOS app.
I'm passing in variables via the variables property:
https://developer.apple.com/documentation/foundation/nsuserautomatortask/1418099-variables
Inside the Automator workflow I will then use Get Value of Variable actions to grab the variables that were set on the NSUserAutomatorTask and pass the variables to subsequent Automator actions:
Code looks like this: (simplified; I also check that the variables exist in the workflow)
let workflow = try! NSUserAutomatorTask(url: url)
workflow.variables = [
"singleFilePath": "/image1.png",
"multipleFilePaths": ["/image1.png", "/image2.png"],
]
workflow.execute(withInput: nil)
I'm able to print out the variable values in an alert via an Ask for Confirmation action:
The String variable's value is a simple string: /image1.png
The [String] array variable's value is wrapped in parentheses and each item is quoted:
(
"/image1.png",
"/image2.png"
)
I now run the pictured Automator workflow that first gets a variable's value and then attempts to open those Finder items.
The singleFilePath var works. It's passed on to the Open Finder Items action, and that file is opened by the default application.
Passing multipleFilePaths in the same manner does not work. No files are opened. Automator displays the error:
The action "Open Finder Items" was not supplied with the required data.
The action is "Open Finder Items", so there must be some way to pass multiple file paths to this action.
My questions and solutions in order of preference are:
Why is the default variable array/list format not working when passed to the subsequent action? Is there any way to pass or parse the array variable in a compatible format?
Can we use a single Run AppleScript action to reformat the array variable into a format that can be passed to subsequent Automator actions? (I'd like to continue to chain Automator actions rather than run pure AppleScript).
Open Finder Items actions can open an array of items if used in a normal non-variables workflow. And it's seemingly in the exact same format.
As a control to test this, rather than the variable, I'm using the Get Specified Finder Items action.
I then use a View Results action to inspect what is sent to Open Finder Items.
The results are seemingly exactly the same as when I parse the variable:
(
"/image1.png",
"/image2.png"
)
This workflow does correctly run the final action and open the files.
So Open Finder Items should work with the data I'm setting in the variable. I'm unsure why the variable data cannot be opened but manually-picked files can.
I opened a DTS ticket for this issue and received the following response:
I’m sorry to say the engineers working on this have confirmed that yes, it’s a bug, and no, there isn’t a workaround for sandboxed apps. They’ve also noted this isn’t a regression in behavior from previous releases.
I'd like to export all of my favorited photos/videos on a weekly basis to a zip file or directory. Is there an apple script/automator workflow that can do this that I can schedule to run?
Thanks for your response, I've tried what you suggested but get this error (please note that automator is automatically changing the text "using originals true" to "with using originals":
If we open up the scripting dictionary for Photos and search for “favorite”, we see the following:
There is an album object available from the root Photos application that contains all of your favorited items. Perfect! Now we need to export them… dictionary, what do you have to say on the matter?
There is a command in Photos that exports specified media items to a filesystem location. That's exactly what we need! So, so far, we have this in our script window:
tell app "Photos"
export every media item in favorites album to [export location here] ¬
using originals true
end
Obviously, you should replace [export location here] with the location you want to export to (via a file or POSIX file specifier). If you want to compress them into a zip file now, that should be pretty easy, too. In this case, since this functionality isn't provided by any preinstalled system application (that I am aware of), we can outsource the job to a command line utility called zip:
set quoted_out_location to quoted form of POSIX path of [export location here]
do shell script "zip -r " & quoted_out_location & space & quoted_out_location
And that's it! From there you can move the resulting zip file wherever you need using System Events or Finder or whatever you please, and delete the intermediate folder if you want. If this needs to run automatically on a regular basis, the easiest option by far is to embed the script in an Automator Calendar Alarm workflow, and attach it to a recurring calendar event. That's not too hard to find with a quick Google search, and this answer is long enough already.
I've seen a lot of questions about this on the interwebs but no answers. Is there a way to refer to an Automator 'variable' within AppleScript? I'd like to do some string manipulation as part of a workflow. I've worked around this by using Get Variable and passing them into temporary files, but it's kind of ugly.
I was trying the same ting as Steven. My conclusion is that when you run a flow inside the "Automator" application then your applescript can access Automator-varaibles via the Apple Script "Automator Suite" interface. For example:
set my_variable to value of variable "The Variable" of workflow 0 of current application
display dialog my_variable as text
set my_variable to "Test"
But if you save the flow as a stand alone application then it does NOT include the "Automator Suite" into the application and therefore the above script will no longer function :-(
An AppleScript used in a workflow accepts two parameters: input, or the output of the previous workflow, and parameters, the options set in the workflow's UI (if applicable). If the string you are manipulating is part of the workflow's input, it will be in input.
More information is available here.