Home > Software engineering >  python unexpected EOF when running os.system()
python unexpected EOF when running os.system()

Time:10-26

Task: I'm trying to run a system command in python. The command is a webhook for IFTTT that send a notification to my phone. I followed this article here.

I tried running it via bash but didn't have much luck with the argument formatting (I don't know bash, at all). So instead I am using python. Here is my code.

import os
command = """curl -X POST -H "Content-Type: application/json" -d '{"value1":"I'm frustrated"}' https://maker.ifttt.com/trigger/notify_phone/with/key/<my_key>"""
os.system(command)

Notice how my "value1" for json is "I'm frustrated". The single quote in I'm is not appreciated by the computer, and I cannot figure out why. I'm presented with the following error:

sh: -c: line 0: unexpected EOF while looking for matching `"'
sh: -c: line 1: syntax error: unexpected end of file

I've also tried the following commands and I'm greeted with the same error, so I'm really confused.

command = """curl -X POST -H "Content-Type: application/json" -d '{"value1":"I\'m frustrated"}' https://maker.ifttt.com/trigger/notify_phone/with/key/<my_key>"""

and

command = """curl -X POST -H "Content-Type: application/json" -d '{"value1":"I\\'m frustrated"}' https://maker.ifttt.com/trigger/notify_phone/with/key/<my_key>"""

What am I doing wrong?

CodePudding user response:

I tried running it via bash but didn't have much luck with the argument formatting (I don't know bash, at all). So instead I am using python.

Ah, but you're using os.system which runs in a subshell, so you're still using a shell, likely bash or an equivalent. So you haven't avoided the same escaping challenge.

Task: I'm trying to run a system command in python.

Looking at your question, I think you're actual task is to make a web request.

curl -X POST -H "Content-Type: application/json" -d '{"value1":"I'm frustrated"}' https://maker.ifttt.com/trigger/notify_phone/with/key/<my_key>

Okay, so you're making an HTTP POST of Json data. If you're comfortable in python, why call out to a different executable to make an HTTP request? requests is the most common way of doing this in python.

Starting from the example in that link, something like

r = requests.post('https://maker.ifttt.com/trigger/notify_phone/with/key/<my_key>', data={'value1':'I\'m frustrated'})

-H "Content-Type: application/json"

I believe you'll get this for free when you pass an object as data. But it's certainly possible to set it explicitly with requests.

For what it's worth, the escaping problem you're hitting is a quirk of bash syntax: \' does not escape a single quote in a single quoted string. Think of ' in bash like a "toggle"; one ' disables special characters, another ' re-enables them. Since \ would be a special character in the phrase '\'', it is not a valid expression.

Peter Wood says,

It's better to build commands using subprocess so they get escaped/quoted correctly.

The reason subprocess works so much better than os.system is because you get to specify the arguments as separate values in the call, so you don't need to escape anything for the shell itself. In fact, you don't need a shell to invoke curl.

subprocess.run(["curl", "-X", "POST", ..., ... ], capture_output=True)

Your POST data would still have to be formatted as valid json:

... '-d', '{"value1":"I\'m frustrated"}'

Python has sane, standard quote esacping for '.

>>> print('I\'m working')
I'm working

If you really wanted to do this in bash shells, it is possible through a number of mechanisms. Here's one:

curl -X POST -H "Content-Type: application/json" -d '{"value1":"I'\''m frustrated"}' http://httpbin.org/post

But to reiterate, just use python's requests. It will handle encoding your Json data properly, and if you should ever care about the return of the web request, handling that in requests will be much, much easeer than it would dealing with curl's output.

  • Related