Jump to content

selection in macos + keyword


Recommended Posts

Hi guys, I have a workflow in which I use the (selection in macOS) as the "query" in a bash script (it runs an OCR on the selected file). To do this, I use the "argument: Selection in macOS" of the "hotkey", but I would rather use a keyword (rather than a hotkey) to run the script (so that I can for instance more easily run the OCR_english and OCR_dutch versions of the script). Is this possible?

Link to comment
1 hour ago, Misha said:

Is this possible?

 

Not easily, no. If you're using a keyword, then the active application is Alfred (as you're entering your query into it), which isn't where you want to get your selection from.

 

You can work around it in a workflow by attaching your keyword to a Run Script action that simulates a ⌘C keypress and then uses pbpaste to grab the contents of the pasteboard.

 

That doesn't work quite a smoothly as using Alfred's built-in feature, however. Your best bet is therefore to use a Hotkey.

 

Link to comment

Hi @Misha, I did a small workflow as example to show you multiple ways of doing it (using a: File action, a Hotkey or a Keyword). This way you can use the way you find it best for your use case. Myself I would use the file action since you want to work with files and this is made for that... but any method should works great

 

Here is the workflow: https://nofile.io/f/O7scHb0o3rm/File+Selection+&+OCR_Keywords.alfredworkflow

 

Hope this helps!

 

 

Edited by GuiB
Link to comment
  • 1 year later...

@GuiB Thanks for posting the following workflow:

 

On 7/19/2017 at 9:43 PM, GuiB said:

 

This was extremely helpful! Similar to @Misha I was trying to get a keyword to operate like a hotkey - which passes the selected items from Finder - and your workflow helped tremendously.

 

That said, even after following the example, I was not able to get my workflow working with more than one file at a time (i.e., when more than one file is selected in Finder and you want to run the script on each of the files). It just runs for one of the files that are selected. Is there anything special that needs to be done to your example workflow when working with multiple files?

 

For example, I'd like to send a few files to an automator script. When I run the script from a file action on one or more files, I use the following bash script (with input as query):

files="{query}"
IFS="    "
set $files
for file in $files
do
    automator -i "$file" "/Users/NAME/Library/Services/NAME.workflow"
done

It works great, but I was hoping to run the script from a keyword, too. 

 

To accomplish this, I tried adapting your workflow. First, I changed the osascript step to the following (adding the first line😞

set my text item delimiters to tab

tell application "Finder" to return POSIX path of (selection as text)

Then, I changed the bash script step to the following (with input as argument😞

query=$1

IFS="	"
set $1

for file in $1
do
	automator -i "$1" "/Users/NAME/Library/Services/NAME.workflow"
done

However, it only ever works on one of the files that are selected in Finder. From what I can tell after digging around, it looks like the number $1 is telling the bash script to only run on the first file. Is this correct?  If so, how should your model be adapted to run for each file?

 

Oddly enough, if I attach the osascript step (above - second snippet of code provided) to the original file action's bash script (above - first snippet of code provided), it does the same thing when run from a keyword. As a result, I think the problem is with the osascript step (above - second snippet of code provided)? I added the "set my text item delimiters to tab" to your script, but perhaps it needs a few more changes (i.e., so that it copies the names of each file in the same manner that a hotkey would using the macOS selection option)?

 

Thanks for your help (and for posting this example workflow)!!

Link to comment

@Jasondm007 I've updated the script for you to work with a multi selection. In short, you were not too far from having it. It's mainly your loop over your file list. I have changed it to:

 

# Change IFS to TAB and expand into an array
IFS=$'\t' filesListArr=($@)

# Loop over the file list array
for file in "${filesListArr[@]}"
do
    # Your script to be run
    automator -i "$file" "/Users/NAME/Library/Services/NAME.workflow"
done

 

Here is the updated workflow:

https://nofile.io/f/8ugP4mSgOMu/File+Multi+Selection+&+OCR_Keywords.alfredworkflow

 

Also, I've edited every action to work with a multi selection, so you get an example with a File Action, a Hotkey and a Keyword action

Edited by GuiB
Link to comment

@GuiB Thanks for getting back to me, and for taking a look at this. I really appreciate it.

 

By chance, does the osascript need to be updated? I'm still having the same issue. 

 

When troubleshooting - to see what the file list looks like - I attached that step to a clipboard, and the files look a little different (one of the files looks correct, but the other has "Macintosh HD" specification). Is it possible that this is the step with the problem?

 

Thanks again for all of your help!

Link to comment

Yes, if you look inside the AppleScript node, I've set it as you did. However, now that you mention that, you're right that the first path uses /Users/ and the other /Macintosh HD/. I tried another way before switching to yours since I didn't test it first and then when I tested your I thought everything was fine. But my other version was to loop over the Finder selection to build a string delimited by TAB. I've tried again my version and with it I get all "/Users/" kind of paths

 

Here is my modified AppleScript code:

tell application "Finder" to set theSelection to selection as alias list
set theFileList to ""
repeat with i from 1 to count of theSelection
	set theFileList to theFileList & "\t" & POSIX path of item i of theSelection as string
end repeat

return theFileList

 

And here is the new Workflow if you want to see it:

https://nofile.io/f/scHz3m70RpG/File+Multi+Selection+&+OCR_Keywords.alfredworkflow

 

Let me know how it goes!

 

Link to comment

@Jasondm007 I just thought this morning that we don't have to create a new string if we combine both of our version... just need to update the array in the AppleScript and set the text item delimter to tab and output the array as a string. So here is my new version

 

set my text item delimiters to tab

tell application "Finder" to set theSelection to selection as alias list

repeat with i from 1 to count of theSelection
	set item i of theSelection to POSIX path of item i of theSelection as string
end repeat

return theSelection as text

 

And an updated Workflow example here: https://nofile.io/f/aqMoJwmGf8O/File+Multi+Selection+&+OCR_Keywords.alfredworkflow

Edited by GuiB
Link to comment

Ok, I've tested it with a real action to do on each file. I didn't tested completely before, I just tested by outputing the path string to look at it, but now tested to do a real action on multiple files (copy them to a new file) and saw that the it didn't work on the last file in the list. So a little trimming to remove the whitespace on the file path worked. Therefore, here is an updated version that should work!

 

@Jasondm007 sorry for the little problems with my other versions. I think this one is good now, but let me know if you still have problem!

 

Here is the link to the new workflow: https://nofile.io/f/nTBEXw6Ku3U/File+Multi+Selection+&+OCR_Keywords.alfredworkflow

 

And here the modified script for the Run Script that execute the action

# Change IFS to TAB and expand into an array
IFS=$'\t' filesListArr=($@)

# Loop over the file list array
for file in "${filesListArr[@]}"
do
	trimmedPath="$(echo -e "${file}" | tr -d '[:space:]')"
	# Your script to be run
    automator -i "$trimmedPath" "/Users/NAME/Library/Services/NAME.workflow"
done

 

Link to comment

@GuiB This is awesome!! In fact, I think that Alfred ought to include more examples like this for those of us newbies or scripting novices (e.g., in the Getting Started or Examples menu)!! Thanks a ton!

 

I'm not sure if I'm doing something incorrectly, but I wasn't able to get the Run Script (bin/bash) to work as specified in your previous post above. By making the following small changes, however, it seems to be working great (changing the subsequent reference in the automator line from $trimmedPath to $file).

# Change IFS to TAB and expand into an array
IFS=$'\t' filesListArr=($@)

# Loop over the file list array
for file in "${filesListArr[@]}"
do
	trimmedPath="$(echo -e "${file}" | tr -d '[:space:]')"
	# Your script to be run
	automator -i "$file" "/Users/Name/Library/Services/Name.workflow"
done

Does this look correct to you? It seems to be working, but I'm concerned it will break! Thanks!

 

To make things easier for us to test, I've created a workflow that uses an actual bash script to move files to a user's downloads folder. The workflow has been uploaded for you here: https://nofile.io/f/ZWURw7ub90s. The file action at the top of the workflow operates perfectly (yellow - top). However, I'm having problems implementing your approach with a keyword (purple - middle). When it runs, it always drops one of the files (e.g., if run on 4 files, it will work for 3 of them, etc.). However, the hotkey - which runs the same bash script - operates perfectly (pink - bottom). Based on this example, how would you suggest applying your model to the keyword example in the uploaded workflow (purple - middle)? 

 

For quick reference - and for others who may not want to download the uploaded test workflow - below you will find a (1) screenshot of it, as well as the code from the (2) osascript and (2) bash scripts (purple - middle):

 

Screenshot

example.thumb.jpg.4348e3a964a671bc69490cfffa504890.jpg

 

 

Osascript

set my text item delimiters to tab

tell application "Finder" to set theSelection to selection as alias list

repeat with i from 1 to count of theSelection
	set item i of theSelection to POSIX path of item i of theSelection as string
end repeat

return theSelection as text

Bash Script

# Change IFS to TAB and expand into an array
IFS=$'\t' filesListArr=($@)

# Loop over the file list array
for file in "${filesListArr[@]}"
do
	trimmedPath="$(echo -e "${file}" | tr -d '[:space:]')"
	# Your script to be run
    mv -i "$file" ~/Downloads
done

 

Thanks for your help!

Link to comment
29 minutes ago, Jasondm007 said:

By making the following small changes, however, it seems to be working great (changing the subsequent reference in the automator line from $trimmedPath to $file).

By removing this small part, you made it work as before. Like you said, while doing a real test I saw that the last element in the list of selection wasn't working and found out it was because of problem with whitespaces. So I trimmed the surround spaces with the trimmedPath="$(echo -e "${file}" | tr -d '[:space:]')" line and the trimmedPath variable include the file variable but trimmed. However, now I did more tests and found out there's still a bug with this line and now use an alternative using piping to xargs to do the trimming instead.

 

Now, this seems to work, but again, let me know if you still have a problem!

 

Here is the updated script for the Run Script:

# Change IFS to TAB and expand into an array
IFS=$'\t' filesListArr=($@)

# Loop over the file list array
for file in "${filesListArr[@]}"
do
    trimmedPath="$(echo -e "${file}" | xargs)"
    # Your script to be run
    mv -i "$trimmedPath" ~/Downloads
done

 

Here is your script but updated with this fix: https://nofile.io/f/hjT4JFt6AVw/-+Example+File+Multi+Selection+Tests.alfredworkflow

 

And here is my workflow with this fix: https://nofile.io/f/c8K4KEpkjWa/Example+File+Multi+Selection.alfredworkflow

 

---------

To explain a little more why the other script doesn't work, but worked before on my side. The problem is that I was removing all the space in the file path, while the second one doesn't (it just trim the begining and end of the string; which is what I wanted in the begining, but did it too fast ;) ). I'm used to never insert space on my file name, so that's why it worked before. But, now I tested iton a file that's inside my "Google Drive" and it removed the space inside to output it like "GoogleDrive" and broke it. Now we should be good ;)

Edited by GuiB
Adding more explanation why the other script doesn't work
Link to comment

@GuiB Thanks a ton for tinkering with your script, and for the detailed explanation. This was tremendously insightful, and has helped me understand how to fix a bunch of my partially-operational workflows. This is awesome!

 

I hate to impose on you any more than I already have, but I am curious if you had any advice for dealing sending multiple files to AppleScripts (i.e., instead of sending the files to a bash script at the end, how might you split the file list for an AppleScript to operate)? A lot of my workflows use AppleScripts, and I'd love to make them work with multiple files, too. While I should probably start learning more bash, I often gravitate towards AppleScripts because I find them easier to understand and test with Mac's Script Editor (as I'm sure other newbies do as well). Alfred - the app, its developers, and the community - are great, but I wish the app contained more examples like the one that you created. Thanks again for all of your help!

Link to comment

@Jasondm007 Here is the same thing, but using AppleScript.

 

In short, change the last Run Script to an AppleScript one with this script:

on trim(theText)
  return (do shell script "echo \"" & theText & "\" | xargs")
end trim

on run argv
  set my text item delimiters to tab
  set theFileList to text items of (item 1 of argv)
  repeat with theFile in theFileList
    set fileAlias to (POSIX file trim(theFile) as alias)
	tell application "Finder" to move fileAlias to folder (path to downloads folder)
  end repeat
end run

 

Here is a new workflow with this inside in case it is easier to make it work: https://nofile.io/f/qvNgR5gw0pe/-+Example+File+Multi+Selection+Tests.alfredworkflow

 

 

This one should work and give you something to play around when using AppleScript ;)

 

All the best!

Edited by GuiB
Simplified the AppleScript a bit
Link to comment

@GuiB This is amazing!! Thanks a ton.

 

Am I correct to say that - in most applications of this method - only the highlighted portions of the following image would change (i.e., the portion of the script beginning with "set fileAlias ..." and ending with "... downloads folder)")? So, if I were to create another workflow, I'd be adding its new code to that highlighted portion and referencing each file with the "trim(theFile)" variable? Thanks!!

 

Script.jpg.37d84dd9878b6b1b8b2fc4694e02893d.jpg

 

 

Link to comment

@GuiB Please ignore that last question.

 

46 minutes ago, Jasondm007 said:

Am I correct to say that - in most applications of this method - only the highlighted portions of the following image would change (i.e., the portion of the script beginning with "set fileAlias ..." and ending with "... downloads folder)")? So, if I were to create another workflow, I'd be adding its new code to that highlighted portion and referencing each file with the "trim(theFile)" variable?

 

I think I understand how it works now. In most cases, it's just the "tell application ..." line(s) that will get changed, correct? And, subsequent references to each file are to the "fileAlias" variable?

 

For example, the code below follows your approach to open each file in the Preview app (nothing special about Preview here - I just wanted to make sure that I understood how everything worked). 

 

on trim(theText)
  return (do shell script "echo \"" & theText & "\" | xargs")
end trim

on run argv
  set my text item delimiters to tab
  set theFileList to text items of (item 1 of argv)
  repeat with theFile in theFileList
    set fileAlias to (POSIX file trim(theFile) as alias)
	tell application "Preview" to open fileAlias
  end repeat
end run

Thanks!

Link to comment
  • 2 months later...
  • 3 months later...
  • 5 months later...

@GuiB I was wondering if I could ask a quick question related to our previous discussion/working examples above?

 

More specifically, I occasionally have issues when trying to use your working example to connect a File Action to Run Script set as an AppleScript. Namely, the script often only runs on the first file selected and not the others. 

 

For example, this morning I was trying to create a quick workflow that will work for multiple selections at a time with a (1) a keyword through Finder, and (2) a file action.

 

workflow.jpg.dff7b71f6373af81ba2c033447d7f415.jpg

 

The workflow merely places the files on the clipboard as images (I have one app in particular that is a little finicky about pasting things). In any case, it works perfectly from the keyword for multiple selections. However, it only works for the first selection when run from a file action. It's virtually identical to your working example (which moved files to the user's downloads folder). I've highlighted the only real difference below:

 

Images.jpg.226eee95340415e94513644bd3518a00.jpg

 

Any ideas what might be causing the problem? Does the text from the file action have to be processed before being handed off? I tried creating another step after the file action, so that I could try and get the list of files to look identical to the list that is handed off by the keyword-based version, but I was never quite able to get it to work for multiple selections at a time.

 

I've uploaded the workflow here: Download Workflow

 

Hope this finds you well. Thanks for any help you can lend!

Link to comment

@Jasondm007, you problem is that when you are directly connecting to the File Action you are receiving a list of files in "argv", but on the second example ("imc") you are sending a tab delimited list of file paths that consist as a single string as input. Therefore, on your first example you can iterate over the list input of you script and not just the first argument ("argv 1"). 

 

Here is a modified version: https://d.pr/f/0BOBGT

 

I added a delay to better make sure the item has time to be copied (I didn't have all the items on my clipboard viewer if not), but you can play with it to make it work for your case.

Link to comment

@GuiB Thanks a ton for taking the time out to take a look at this for me. Your explanation and this working example is incredibly helpful. Much appreciated.

 

By chance do you have any recommendations for how to test for these types of variable-related problems? I use the debugger and often create intermediate steps where I copy a variable to the clipboard, so that I can make sure that everything looks OK. However, these problems drive my crazy!! 🤪

 

Thanks again!!

Link to comment

@Jasondm007 

honestly I don't have many tricks for trying to get some outputs to the debugger and carefully looking at the information there. Sometimes I look at what is happening before, sometimes after a node, trying to output a variable and analyzing it to see if it's right, adding tests inside the script to try to pinpoint where the problem occurs (see if a loop is looping correctly, if a variable is set correctly...)...

 

In this case, you could see that from the "imc" Keyword node a string was output with paths separated by tab, but on the "Image..." File Action node you could see that the paths are separated by "comma" in the debugger (if you connect the Debug node just after the File Action). This way you have a little cue that the outputs are different. Then you can inspect the "item 1 of argv" and see if they match and if not try to find out why they are different.

 

With that said, keep in mind that from an Alfred node that output a list of items you would get a List, but when chaining multiple nodes (different Run Scripts or other actions) one output is passed to the next node as one string. So, in order to get multiple items we have to build this string we can manipulate it in the next node to retrieve the different items (that's why I'm passing the paths with tabs as separators as a trick to pass multiple items so we can easily split them afterward in the next node). You can use any delimiter that you want of passing JSON string or something else (like we talked on this thread:

 

To get back to your workflow above, actually you don't have to pass the output of your AppleScript from your "imc" keyword node and depending on what you want to achieve it could be easier to directly loop over the selection list that you get from the Finder instead of modifying the list to a single string with tab delimiter (especially if you want to connect it to another AppleScript). Here is a modified workflow to show you how it looks if you use the selection directly: https://d.pr/f/pvtilq

 

Also, I don't remember exactly why I added the Trim function to make sure to trim the files path (maybe to make sure one of the paths doesn't have an extra whitespace in it in case we output as one string), but if you use the passed list from Alfred file action or the Finder selection, then you shouldn't have to trim the paths.

 

Hope this helps a bit! :)

 

Best

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...