1

I need to run a bash shell command (Debian) through Python and collect the output.

The command is

curl -H "Content-type:application/json" https://api.example.com/api/v1/login -d '{ "ldap": true, "username": "myusername", "ldapPass": "mypassword", "ldapOptions": {} }'

With the right URL, userid, and password substituted in, this command works in the bash shell. I would like to run this command in a Python program using subprocess.Popen(cmd...)

Obviously I have to assign something to cmd before calling Popen(cmd), but I can't figure out what. I tried adding escape characters like this:

cmd = "curl -H \"Content-type:application/json\" https://api.example.com/api/v1/login -d '{ \"ldap\": true, \"username\": \"myusername\", \"ldapPass\": \"mypassword\", \"ldapOptions\": {} }'"
p = subprocess.Popen(cmd.split(" "), stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
(child_stderr, child_stdout) = p.communicate()

It didn't work, and threw an exeption.

I then tried building the cmd array by hand, and then not splitting it during the Popen call:


cmd = ["curl","-H","\"Content-type:application/json\"", "https://api.example.com/api/v1/login", "-d","'{ \"ldap\": true, \"username\": \"myusername\", \"ldapPass\": \"mypassword\", \"ldapOptions\": {} }'"]

print(cmd)
print(" ".join(cmd))

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
(child_stderr, child_stdout) = p.communicate()

This didn't work either and threw an exception.

Interestingly, when I copied the output of " ".join(cmd), and ran it in the shell, it worked fine.

I have used other cases like

cmd = ["ps", "-ef"]

and it worked fine.

How can I assign the proper value to cmd (with its single and double quotes) so that it will run properly using Python's subprocess.Popen()?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Jay Godse
  • 15,163
  • 16
  • 84
  • 131
  • What was the exception in the second example? – mkrieger1 Oct 01 '20 at 19:51
  • It should just be `'-H', 'Content-type:application/json'` -- no extra quotes. The syntactic quotes are for the shell, not for curl; when you don't have a shell, you don't need them. – Charles Duffy Oct 01 '20 at 20:01
  • Instead of using `" ".join(cmd)` to find an equivalent shell command for testing purposes, use `' '.join([shlex.quote(word) for word in cmd])` (for Python 2, substituting `pipes.quote` instead of `shlex.quote`). – Charles Duffy Oct 01 '20 at 20:04
  • by the way, what's the reason to do it via subprocess and curl and not just use post request using requests? – buran Oct 01 '20 at 20:04
  • @mkrieger1, `"Content-type:application/json"` isn't a valid header; the quotes on the beginning and end aren't legal. Same for the `'`s on the beginning and end making the body no longer a valid JSON document. So I'd expect the server to throw an error. – Charles Duffy Oct 01 '20 at 20:11
  • @buran - I later tried using urllib. I could not get it to work. My IT guy gave me the curl script, and it worked. Writing a program for this is not working using any mechanism. – Jay Godse Oct 02 '20 at 12:47
  • I would suggest using `requests` instead of `urllib`. and here is nice [curl to requests converter](https://curl.trillworks.com/) to help you start if you choose to give it a try – buran Oct 02 '20 at 12:51

0 Answers0