-1

I am trying to run this shell script in Python:

set THENAME = PETER
echo THENAME = $THENAME

So in Python3 I do this:

import subprocess

shell_command = "set THENAME = PETER"
subprocess.check_call(shell_command, shell=True)
shell_command = "echo THENAME =$THENAME"
subprocess.check_call(shell_command, shell=True)

So I expect when I run the python code on Linux or Unix I get:

THENAME=PETER

But instead I get:

THENAME=

What am I doing wrong?

TJ1
  • 7,578
  • 19
  • 76
  • 119
  • Which shell? You're demonstrating csh syntax; the shell tag is for POSIX-family shells. – Charles Duffy Jun 02 '22 at 18:24
  • (also, `subprocess.check_call(..., shell=True)` uses `/bin/sh`, which **is** a POSIX-family shell, by default; it's normal for csh code to fail there). – Charles Duffy Jun 02 '22 at 18:24
  • @CharlesDuffy thanks for your comment. Please see my comment below the "that other guy" answer. Do you have any suggestion? – TJ1 Jun 02 '22 at 18:49
  • My suggestion comes down to what that other guy told you. See https://ideone.com/LikQHZ showing code with appropriate corrections working in an online interpreter. – Charles Duffy Jun 02 '22 at 18:59
  • @CharlesDuffy thanks again. But when I use that answer, and then when I manually on the Unix terminal type: echo THENAME=$THENAME I get this error message: THENAME: Undefined variable. – TJ1 Jun 02 '22 at 19:02
  • No executable can ever set variables for its parent process without that parent process's active involvement. This is not something that is expected to work, at all, ever. – Charles Duffy Jun 02 '22 at 19:03
  • If that's what you're trying to do, then this is more properly a duplicate of [How to set environment variables of parent shell in Python?](https://stackoverflow.com/questions/35780715/how-to-set-environment-variables-of-parent-shell-in-python), or [Is it possible to change the environment of a parent process in Python?](https://stackoverflow.com/questions/263005/is-it-possible-to-change-the-environment-of-a-parent-process-in-python) – Charles Duffy Jun 02 '22 at 19:04
  • ...keep in mind, that's not a Python limitation, that's a UNIX-process-model limitation. It's why you can't run `ssh-agent` on its own but need to run `eval "$(ssh-agent)"`, for example. – Charles Duffy Jun 02 '22 at 19:05
  • (well, need to run `eval "$(ssh-agent)"` _if you want `ssh-agent` to hand off environment variables to your shell_) – Charles Duffy Jun 02 '22 at 19:33

1 Answers1

1

There are two problem with this:

  1. This is not how you set a variable in a shell. Instead, the syntax is THENAME=PETER.
  2. Each command runs in a subprocess, meaning they don't share variables. There is no great way to "save" the variables that ended up being set in a subprocess.

You can fix the syntax and run both commands in the same subprocess:

import subprocess
shell_command = "THENAME=PETER; echo THENAME =$THENAME"
subprocess.check_call(shell_command, shell=True)

or pass in the variable in the environment for the command:

import os
import subprocess
shell_command = "echo THENAME =$THENAME"
subprocess.check_call(shell_command, shell=True, env=dict(os.environ, THENAME="PETER"))

or set it in your Python process so that all future subprocesses will inherit it:

import os
import subprocess
shell_command = "echo THENAME =$THENAME"
os.environ["THENAME"]="PETER"
subprocess.check_call(shell_command, shell=True)
that other guy
  • 116,971
  • 11
  • 170
  • 194
  • thanks for the answer. I tried the 3rd method and it prints the correct value at the output. But on the same Unix terminal that I ran the Python code when I type: echo THENAME=$THENAME I get this error message: THENAME: Undefined variable. Basically what I need to do is instead of manually running some of the shell commands I want python to run some of them. – TJ1 Jun 02 '22 at 18:47
  • 1
    @TJ1, `THENAME: Undefined variable` is not an error message that a POSIX-family shell will emit in a default configuration (you need the non-default `set -u` for undefined variables to be considered erroneous at all). So your test environment has something going on you haven't told us about. – Charles Duffy Jun 02 '22 at 19:00
  • 1
    @TJ1, ...also see https://ideone.com/P96a7m, showing the 3rd method working perfectly. If we are to give guidance on how to fix a problem, we need to be able to see that problem ourselves. – Charles Duffy Jun 02 '22 at 19:01
  • @CharlesDuffy thanks again. What other information do I need to provide other than I am testing this on a Unix system? – TJ1 Jun 02 '22 at 19:04
  • 1
    _How_ you're testing it (and what properties you're testing for) would be a start. If what you're testing is whether the variable is visible _to the parent shell after the Python process exits_, as opposed to visible _to its children_, that would make this a completely different question. – Charles Duffy Jun 02 '22 at 19:06
  • @CharlesDuffy thanks so much for the explanation. So if I put everything I am doing on the terminal manually in a python code, that should work correctly? Is the python code what you call children? – TJ1 Jun 03 '22 at 16:19
  • The Python _interpreter_ is a child of the shell you start it from (if you start it from a shell; if you start it from systemd, f/e, then it's a child of systemd). And when you start a shell from Python, that shell is a child of Python; so shell1->Python->shell2 means that shell2 is separated from shell1 by two process boundaries, and _definitely_ can't modify its memory state. – Charles Duffy Jun 03 '22 at 16:38
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/245305/discussion-between-tj1-and-charles-duffy). – TJ1 Jun 03 '22 at 16:43