0

I'm trying to run bash code via python. Normal statements (netstat, for example) work. If functions like the one below, however, don't. What should I change in order to run the following code correctly? Thanks in advance

>>> import os
>>> import subprocess
>>> 
>>> os.setenv['a']='test'
>>> _c = 'if [ "$a" == "test" ]; then echo $a; fi'
>>> print(subprocess.Popen(_c, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8'))
/bin/sh: 1: [: anto: unexpected operator
pidgey
  • 245
  • 1
  • 3
  • 15
  • Check [Python subprocess/Popen with a modified environment](http://stackoverflow.com/questions/2231227/python-subprocess-popen-with-a-modified-environment) – sal Oct 07 '16 at 22:45
  • Doesn't seem to be the issue... `print(subprocess.Popen("echo $a", shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')) ` works perfectly – pidgey Oct 07 '16 at 22:58
  • I think it has to do with what the `shell=True` flag actually does, which is to start a shell and pass it the commands in the string. If I am correct, what you are trying to do, gets translated to a `sh -c "if [ \"$a\" == \"test\" ]; then echo $a; fi"` on your linux shell. If you run that, you get the same error. How to get out of it, though, escapes me at the moment. Hopefully someone with more insights can pitch in. – sal Oct 07 '16 at 23:28
  • That actually makes sense. Previous attempts gave me `if [ "$a" == "anto" ]; then echo $a; fi; : No such file or directory` as output, which is what I get trying to execute it with bash – pidgey Oct 07 '16 at 23:36
  • 2
    Wait: actually, try changing `[ "$a" == "test" ]` into `[ "$a" = "test" ]` – sal Oct 07 '16 at 23:39
  • So, I think the real problem is that your code is for `bash` and instead on Unix, subprocess will actually launch by default `sh`. These two shells are mostly equivalent, except the `equality` test is different. I'll add an answer, hopefully I got it right. – sal Oct 07 '16 at 23:54

1 Answers1

2

The command you are trying to run in the subprocess is following the bash shell syntax, where the string equality test is performed via ==. Now, on Unix with shell=True, the shell defaults to /bin/sh where instead the equality test is performed via a simple =. The two options you have here are:

  1. follow sh syntax in your script
  2. explicitly call '/bin/bash' as the executable to be run by adding executable='/bin/bash' to the Popen

As for option (1), replace _c as follows and it should work fine:

import os, subprocess
m_env = os.environ
m_env['a'] = "test"
_c = 'if [ "$a" = "test" ]; then echo $a; fi'
print(subprocess.Popen(_c, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8'))

That prints out "test".

pidgey
  • 245
  • 1
  • 3
  • 15
sal
  • 3,515
  • 1
  • 10
  • 21
  • 1
    Using the shell syntax, an empty string gets returned. – pidgey Oct 08 '16 at 00:07
  • 1
    I think `os.environ` is the right way to pass environment variables. Somehow I can't find any reference to setenv. This is working on my ubuntu machine. – sal Oct 08 '16 at 00:13