How do I access 'Dictionary' variables in a shell script?
You can use the “process tokens” AppleScript command of the Keyboard Maestro Engine.
(I was going to start a new thread, but I found this and figured it would be better to respond here. But I'll phrase my question as if it were a new one, just for clarity.)
Can a Dictionaries Key/Value
pairs be referenced directly from the Execute Shell Script
action ?
ex:
#!/bin/bash
diskutil mount $KMVAR_Dictionary[dictionaryNameHere,keyHere]
exit 0
These are some non-Shell Script ways:
- KM:
%Dictionary[dictionaryNameHere,keyHere]%
- Apple Script:
dictionary keys of dictionaryNameHere "keyHere"
- JSX:
dictionaries["dictionaryNameHere"].dictionaryKeys["keyHere"].value
(Or something like this. I'm not sure.)
I tried the following (using the existing method for calling Keyboard Maestro variables from the Execute Shell Script
action), but it doesn't seem to work:
$KMVAR_Dictionary[dictionaryNameHere,keyHere]
I checked the docs and then found this question/answer
@peternlewis Can you clarify your answer? I'm not exactly sure what you mean or how to accomplish that.
Do I have the syntax wrong or is this not implemented as directly as simple Keyboard Maestro Variables?
Thanks!
No.
The shell script would have to ask the Keyboard Maestro Engine (via AppleScript, presumably using the osascript tool) for the result of the token value using the process tokens
command.
Just to make sure I understand:
- I'd have to
Execute an AppleScript
to get the value and set it to a variable. - And then later (in the same AS) run the shell script I want (via
osascript
) - Which would use the variable set in #1.
?
A few things:
- Feature Request? (Access to Dictionary keys/values via the Shell)
- I'm just mounting and unmounting disks. So I suppose I can just rewrite the entire thing in AppleScript, and avoid the Shell Scripting entirely.- It would seem mounting via AS is handled by something like:
do shell script "diskutil mount UUID"
- Which is what I'm doing already.
- Am I wrong?
Use Case:
- I want to make sure I have the right idea here.
- I've found that using the volume UUID for the disk is the most reliable way of mounting/unmounting (since the name and mount point can change).
- But it's also good to have the name if you want to act on it outside of DiskUtility.app.
- (I want to mount the drives either at will or because of macros need to first mount the drives.)
- So I thought this was a good use case for Keyboard Maestro Dictionaries.
- Setting the "name" and "uuid" as keys for the same "external drive" dictionary.
- And making one dictionary for each drive.
- The alternative is using standard Keyboard Maestro Variables with formulaic names.
- ext__DriveName__name
- ext__DriveName__uuid
How does this sound?
Is there anything that sticks out to anyone as unnecessary or inefficient or likely to cause problems somewhere else?
Thanks!
No. If you are starting with an AppleScript in an Execute AppleScript Action, then there is NO need to use "osascript". Instead you can run a shell script from an AppleScript using the do shell script command.
Example:
tell application "Keyboard Maestro Engine"
set volumeStr to value of dictionary key "Ext_Vol_LaCie" of dictionary "myMac"
end tell
-->/Volumes/LaCie 2Big 3TB
set cmdStr to "diskutil mount " & volumeStr
set resultsStr to do shell script cmdStr
Does this work for you?
Duh!
I worked on it a little more after I posted that, and came up with almost exactly what you just provided. Thanks so much!!
Then I realized, because of some other patterns I wanted to use, that I wouldn't even need to use AS to get the Dictionary value.
Instead:
-
I have a "function" macro, that just acts on a single Keyboard Maestro variable:
- Name: "mountExternalDrive"
- Action:
Execute Shell Script
:diskutil mount $KMVAR_extDrive__ToActOn
- Action:
Set Variable
%Delete%
(just to cleanup)
-
Then I have discrete macros for each drive.
- This way I can mount specific drives, either via other macros or the command window.
- Each of these just sets the argument of "extDrive__ToActOn" to the Dictionary value for that drive and then executes the "mountExternalDrive" function macro above.
- ex:
- Action:
Set Variable
- "extDrive__ToActOn" to %Dictionary[ext__DriveName,UUID]%
- Action:
Execute Macro: mountExternalDrive
The idea, but in JS:
Macro: "Function: mountExternalDrive()"
function mountExternalDrive(uuid) {
# I know this isn't valid. It's just to demonstrate the idea
diskutil mount "$KMVAR_" + uuid
}
Macro: "Mount: Drive 1"
const drive1 = "0000000-1111-22222-333333"
mountExternalDrive(drive1)
Macro: "Mount: Drive 2"
const drive1 = "9999999-8888-77777-666666"
mountExternalDrive(drive2)
Basically trying to follow a functional programming pattern and not repeat multiple actions across macros.
This seems to be a good way to do this in KM.
Have I missed something? Any suggestions?
And thanks again for the quick reply!
No. You said you were executing a shell script. My instructions were based on that. If you are executing an AppleScript, then you would just use tell "Keyboard Maestro Engine" to process tokens
.
Basically, other than variables, whose values are copied in to environment variables before a script (shell or AppleScript) is run, to extract any additional information (dictionaries, tokens, whatever), you will need to use AppleScript to talk to the Keyboard Maestro Engine.
You can. Via AppleScript via the osascript command. Like you can access everything else in Keyboard Maestro Engine. I can't make all the values of all the dictionaries available as environment variables.
Just to circle back to this. I asked this question prior to KM's robust support for JSON. I think the original question is moot now that we can use JSON to pass more complex data to / from the shell.