Passing Variables Into a Shell Script

I have seen several posts about how to pass variables into shell scripts. However, even after several trials I can't wrap my head around this.

I either get this error message by the programme I try to curl to.

addons21/2055492159/web.py", line 199, in handlerWrapper
    if params.get('action', '') == 'requestPermission':
UnboundLocalError: local variable 'params' referenced before assignment

Or the variables are just passed with their names- like %$KMVAR_Answer% instead of e.g. "This would be an answer" .

Any help with this would be much appreciated :pray:

It seems your quotes are not the same:

Thanks very much @JimmyHartington . I already did it with all variations of quotes and the problem persisted. Below is the adjusted version as you recommended.

Unfortunately, I get this error message again:

addons21/2055492159/web.py", line 199, in handlerWrapper
    if params.get('action', '') == 'requestPermission':
UnboundLocalError: local variable 'params' referenced before assignment

If I don't use variables like so

curl localhost:8765 -X POST -d '{"action": "addNotes", "version": 6, "params": {"notes": [{"deckName": "Castree", "modelName": "Cloze (Hide all)", "fields": {"Question": "<div class=“q”>5choice?{{c1::choice burden}}</div>", "Quote": "One whose name is used as an eponym; a person after whom something is named."}}]}}'

The action is successful

Have you tried just using one quote around each variable?
Or maybe building a new variable with the parameters. And the just pass that variable to the shell script

I've quit trying to battle this problem. Instead, I write the text of the script (including the variables) to a txt file. Then, in the next KM action, I specify a shell script from that file rather that from text. Usually, that works. This also allows me to see exactly what the script ends up being.

With one double quote

with one single quote

with one single quote outside and a double quote inside

new variable before 1)

3.)

Unfortunately, all attempts are resulting in the same error message

addons21/2055492159/web.py", line 199, in handlerWrapper
    if params.get('action', '') == 'requestPermission':
UnboundLocalError: local variable 'params' referenced before assignment

I have no more ideas.

Thanks @thoffman666 ! I was thinking about the same, but with Python. Could you perhaps post an example please? I know how to pass variables into a python script. But I'm not sure how to execute the curl command then based on the python script's result

Thanks nevertheless for your time and effort :pray: @JimmyHartington

1 Like

Just change "Execute text script" to "Execute script file" in the "Execute Shell Script" action.

That I know thanks! But I'm not sure if I could execute the curl function via pycurl (or so) without running into additional issues. I would prefer a way where I could directly use the curl command. And apart from the Keyboard Maestro implementation tried so far I'm not sure how do to that. I imagine

1.) compiling the whole command with the variables in a Python script
2.) passing the result of that script into a variable
3.) writing this variable into a .txt file
4.) executing this .txt file via the Execute Shell script option

Is that what you would recommend @thoffman666 ?

Yes, that's exactly what I was suggesting. If nothing else, that allows you to try the exact script in Terminal directly.

Since you’re familiar with Python, I’m going to suggest you stop fighting with curl and shell quoting rules and use the requests module. It allows you to just build a regular Python dictionary and send it as the POST data.

@thoffman666 thanks! Will give that a try!

@drdrang You mean like so

import json
import urllib.request

def request(action, **params):
    return {'action': action, 'params': params, 'version': 6}

def invoke(action, **params):
    requestJson = json.dumps(request(action, **params)).encode('utf-8')
    response = json.load(urllib.request.urlopen(urllib.request.Request('http://localhost:8765', requestJson)))
    if len(response) != 2:
        raise Exception('response has an unexpected number of fields')
    if 'error' not in response:
        raise Exception('response is missing required error field')
    if 'result' not in response:
        raise Exception('response is missing required result field')
    if response['error'] is not None:
        raise Exception(response['error'])
    return response['result']

    invoke("addNotes", notes= [{"deckName": "Default", "modelName": "Basic", "fields": {"Word": "content", "Translate": "content"}, "tags": ["yomichan"]}])

I tried this before in fact. But that didn't work either. Possible though that I made a mistake somewhere in the script as I'm not that familiar with Pythons requests module. However, I didn't get an error message. But it is also not working as nothing gets added to the programme I try adding this to. I'm executing the script as ak.py and literally nothing happens like so:

image

The indentation in your Python script may be the problem.

If it matches what you are showing there, then you have two function definitions but no function applications/invocations, so the script would evaluate to nothing.

The call to invoke :

invoke("addNotes", notes ...

needs to be unindented (full left) to prevent it from being part of the function definition above, and to make it the main expression for evaluation.

1 Like

No, I meant the third-party requests module that I linked to. You may need to install it, but it's much easier to use. More or less like this:

import requests

myURL = "http://localhost:8765"
myData = {"action": "addNotes", "version": 6, "params": {"notes": [{"deckName": "Castree", "modelName": "Cloze (Hide all)", "fields": {"Question": "<div class=“q”>5choice?{{c1::choice burden}}</div>", "Quote": "One whose name is used as an eponym; a person after whom something is named."}}]}}

r = requests.post(myURL, data=myData)
print(r.json())

The myData variable is just a regular Python dictionary, not a JSON string. You can, and probably should, set it up over multiple lines so it's actually readable. I just copied and pasted from your example.

2 Likes

Hey @Maglov,

Welcome to the forum!  :sunglasses:

The best way to get help with something like this is to post a minimal “working” text-case macro for people to test.

If you have code that actually does work in the Terminal then post a same of that as well.

Trying to debug by eye without actually testing is generally a waste of time.


When posting macros to the Keyboard Maestro forum please use these guidelines:

  1. Always post a Macro File.
  2. Always post an image.

This means people won't have to reinvent the wheel to test your macro, and that significantly improves the likelihood that someone will help you.

Folks generally won't download something they haven't eyeballed first, so an image of the macro is crucial.


If you haven't seen these they're worth a moment of your time:

How to Post Your Macro to the Forum

Tip: How Do I Get The Best Answer in the Shortest Time?


--
Take Care,
Christopher Stone

(Keyboard Maestro Moderator)

Thanks @drdrang !

Great! Thanks @ComplexPoint