2

I have the following subprocess/command I run inside terminal:

$ eval $(docker-machine env machine-name)

I assumed the python equivalent would be:

sp = subprocess.run(["eval", "$(docker-machine env {})".format(self.project_machine_name)])

or perhaps:

sp = subprocess.run(["eval", "$(docker-machine", "env", "{})".format(self.project_machine_name)])

However, neither of the above seem to work.

I was wondering, how would I run the above eval within a python script...

N.B. For brevity, assume self.project_machine_name = 'machine-name'

This is not the same as calling a sub-process as it needs to be eval().

Charlie Parker
  • 5,884
  • 57
  • 198
  • 323
Micheal J. Roberts
  • 3,735
  • 4
  • 37
  • 76
  • Possible duplicate of [Calling an external command in Python](https://stackoverflow.com/questions/89228/calling-an-external-command-in-python) – buran Sep 18 '19 at 10:28
  • @buran This is not a duplicate - this is using eval() by fetching the output from a command. – Micheal J. Roberts Sep 18 '19 at 11:18
  • if you want the output of external command instead of subprocess.run() use `subporcess.check_output()`. still it's a duplicate , e.g. https://stackoverflow.com/questions/4760215/running-shell-command-and-capturing-the-output – buran Sep 18 '19 at 11:21
  • how do I run ` command: str = f"eval $(opam env --switch={switch} --set-switch)" res = subprocess.run(command.split(), check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)` **inside of python**? – Charlie Parker Dec 14 '22 at 01:33
  • related: https://discuss.ocaml.org/t/is-eval-opam-env-switch-switch-set-switch-equivalent-to-opam-switch-set-switch/10957 – Charlie Parker Dec 14 '22 at 01:55
  • aren't answers missing `.decode()` for the output? – Charlie Parker Dec 15 '22 at 07:22

2 Answers2

1

try

sp = subprocess.run(['docker-machine', 'env', self.project_machine_name])

More info and additional arguments - in the docs

EDIT: if you want the output, use subprocess.check_output() instead.

buran
  • 13,682
  • 10
  • 36
  • 61
  • I originally tried this, and assumed at that point that it didn't work...my thought is why is this equivalent to `eval($ something)`...? – Micheal J. Roberts Sep 18 '19 at 10:43
  • Nope - sorry this hasn't worked actaully. I need to evaluate the above sub-process. – Micheal J. Roberts Sep 18 '19 at 10:48
  • well, `$ eval $(docker-machine env machine-name)` will construct command `docker-machine env machine-name` and execute it. that is exactly what my suggestion would do. It doesn't make sense to construct a command that will construct another command and execute the later... As described in the [man page](https://www.unix.com/man-page/posix/1posix/eval/): "The eval utility shall construct a command by concatenating arguments together, separating each with a character. The constructed command shall be read and executed by the shell." – buran Sep 18 '19 at 10:52
  • All I can say is if I run the sub-processes manually - it works. And your method doesn't. That is all I can say I'm afraid. – Micheal J. Roberts Sep 18 '19 at 11:03
  • "if I run the sub-processes manually - it works." - I don't get why do you ask if you know the correct syntax to invoke `subprocess.run()` - just use it. And note that "your method doesn't [work]" is extremely uninformative... – buran Sep 18 '19 at 11:07
  • And I am not running `docker-machine env machine-name`, I am running `eval($ docker-machine env machine-name)`. – Micheal J. Roberts Sep 18 '19 at 11:08
  • Manually from the terminal. – Micheal J. Roberts Sep 18 '19 at 11:08
  • It's not uninformative - you've jumped in saying to try something, and when I have tried it - it doesn't work. Please delete answer. The `eval($)` command configures my shell. – Micheal J. Roberts Sep 18 '19 at 11:09
  • how do I run ` command: str = f"eval $(opam env --switch={switch} --set-switch)" res = subprocess.run(command.split(), check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)` **inside of python**? – Charlie Parker Dec 14 '22 at 01:33
  • aren't you missing `.decode()` for the output? – Charlie Parker Dec 15 '22 at 07:22
-1

It depends what you're trying to do but I may be doing something similar. I'm building my dockers in minikube and have a python script that I use to build those dockers.

Before I run the docker build I need to make sure the right environment variables are set, meaning I need to run

eval $(minikube -p minikube docker-env)

Which generates a bunch of statements that you're meant to run in the shell (typically with an eval)

export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.49.2:2376"
export DOCKER_CERT_PATH="/home/aluchko/.minikube/certs"
export MINIKUBE_ACTIVE_DOCKERD="minikube"

# To point your shell to minikube's docker-daemon, run:
# eval $(minikube -p minikube docker-env)

To be able to trigger my builds in python I need these environment variables set when I my docker build commands.

Now there's basically two ways to do this (aside from doing the eval in a wrapper around your script). Both ways involve getting the that string with the export commands.

output = subprocess.check_output(['minikube', '-p', 'minikube', 'docker-env'])
  1. Parse the results of the minikube (or docker-machine command) and set those variables in the shell for future subprocesses. You can be a bit sloppy with the RE since you know the output of the docker-machine command. The shell=True is just for the echo.

    output = subprocess.check_output(['minikube', '-p', 'minikube', 'docker-env'])
    
    import re
    export_re = re.compile('export ([A-Z\_]+)="(.*)"\\n')
    export_pairs = export_re.findall(output.decode("UTF-8"))
    
    build_env = os.environ.copy()
    
    for k,v in export_pairs:
        build_env[k] = v
    
    subprocess.run('echo $DOCKER_HOST', shell=True, env=build_env)
    
  2. A bit sloppier, and more prone to injection attacks, just sandwich the strings together so all your commands are basically a script that starts with a bunch of exports, this isn't nearly as clean and locks you into using the shell=True subprocess functionality, but it does work.

    output = subprocess.check_output(['minikube', '-p', 'minikube', 'docker-env'])
    extended_output = output + b"\necho $DOCKER_HOST"
    print(extended_output)
    
    subprocess.run(extended_output, shell=True)
    
aluchko
  • 19
  • 1
  • 4
  • how do I run ` command: str = f"eval $(opam env --switch={switch} --set-switch)" res = subprocess.run(command.split(), check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)` **inside of python**? – Charlie Parker Dec 14 '22 at 01:33
  • aren't you missing `.decode()` for the output? – Charlie Parker Dec 15 '22 at 07:22