2

These are some dependant commands i am trying to run. My expectation was it will change current folder to abc & list files.

Also after setting z=88, it will print z.

import subprocess
cmd_list = []
cmd_list.append("cd ./abc")
cmd_list.append("ls")
cmd_list.append("export z=88")
cmd_list.append("echo $z")

my_env = os.environ.copy()
for cmd in cmd_list:
    sp = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=my_env, shell=True,text=True)

But unable to get any output for ls and echo $z

Bond
  • 165
  • 2
  • 15
  • The commands are being run in a child process. The changes they make don't have any effect on the parent Python process. – Barmar Apr 12 '20 at 20:13
  • Exported variables are only inherited by children of the shell process, they don't go back to the Python process, and won't be inherited by another child of the Python process. – Barmar Apr 12 '20 at 20:14

1 Answers1

2

You can't do this with multiple calls to subprocess.Popen(). Each call creates a new child process, and changes they make to their environment do not propagate back to the Python process.

You can do it by concatenating all the commands into a single command line to be run by bash -c.

cmd = 'cd abc; ls; export z=88; echo $z'
subprocess.Popen(['bash', '-c', cmd], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=my_env,text=True)

There's also no point in exporting z, since you're not running any child processes of the shell that use the environment variable. Just assign an ordinary shell variable with z=88.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    Are you sure that `stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE` and `capture_output` work together? – Gabio Apr 12 '20 at 20:21
  • Not really, I just copied that from the question. I removed it. I also removed `shell=True`, which it not useful when the first argument is a list. – Barmar Apr 12 '20 at 20:23
  • Yeah, i mistakenly added `capture_output`. @Barmar Is there any way i can split that command ? Because for example, let's say if first command ran successfully and second didn't then i should revert first commands results. – Bond Apr 12 '20 at 20:32
  • You can separate commands with `&&` instead of `;` so the next command only runs if the previous one was successful. – Barmar Apr 12 '20 at 20:50