How does os.system differ from command line?

家住魔仙堡 提交于 2021-02-19 23:52:05

问题


Why does os.system('command') from my python interpreter not have the same output as command from the terminal?

Question explained quickly :

I have

echo $CONFPATH
/home/claramart/Datamart/Parameter

but

os.system('echo $CONFPATH')

0

Why is that?

Details : I want to get my environment $CONFPATH. I'm using python3.5 and ubuntu16.04.2.

I can do this from command line :

echo $CONFPATH
/home/claramart/Datamart/Parameter

This is the answer I want.

Executing it as a python command from command line also works :

python3 -c 'import os; print(os.environ["CONFPATH"])'
/home/claramart/Datamart/Parameter

The thing is, I want to execute this from my python interpreter and not from command line. Executing it from my python interpreter does not work (I am using Pyzo4.4.1) :

print(os.environ["CONFPATH"])
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/python3.5/os.py", line 725, in __getitem__
    raise KeyError(key) from None
KeyError: 'CONFPATH'

I suppose this is strictly coming from my interpreter and not python itself as the python execution from the command line worked. Moreover, I can get $PYTHONPATH from my python interpreter so I guess it simply does not detect all environment variables.

To avoid this and as executing it from command line worked, I wanted to do this as a command line execution from my python interpreter, but none of my 2 command line executions work the way I want to :

os.system('echo $CONFPATH')

0

and :

os.system("""python3 -c 'import os; print(os.environ["CONFPATH"]'""")
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python3.5/os.py", line 725, in __getitem__
    raise KeyError(key) from None
KeyError: 'CONFPATH'
256

Once again and in both cases, it does work for $PYTHONPATH, so I suppose it must go through my interpreter at some point because my problem is specific to that variable $CONFPATH.

Why does os.system('command') from my python interpreter not have the same output as command from the terminal?


回答1:


I think you're expecting there to be one environment. The truth is, every process has its own environment, typically inherited from its parent process. Unfortunately I don't see enough information in your snippets to tell you how to pass this particular value, but we can go through them and see what they actually say.

echo $CONFPATH
/home/claramart/Datamart/Parameter

This shows a shell command echo demonstrating that the shell could expand the parameter $CONFPATH. It does not, however, show whether that was from a shell or environment variable. Later snippets do demonstrate you do have an environment within which it is set, though.

os.system('echo $CONFPATH')

0

Here is a Python function call, in turn calling a C library function, which causes a new shell to be spawned and interpret the given command. Notably this isn't the same shell as any you had running; it is a new /bin/sh process, which inherits environment from the Python interpreter the call was made in. We see that this shell command succeeded (exit value 0) and expanded CONFPATH to nothing, indicating that it was empty or unset in this Python interpreter's environment.

python3 -c 'import os; print(os.environ["CONFPATH"])'
/home/claramart/Datamart/Parameter

Here is an example of a shell command starting a Python interpreter, with a command line causing it to print the environment variable. It succeeded, as the variable was inherited from the shell in which you ran the command.

os.system("""python3 -c 'import os; print(os.environ["CONFPATH"]'""")
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python3.5/os.py", line 725, in __getitem__
    raise KeyError(key) from None
KeyError: 'CONFPATH'
256

Here one is wrapped in another; from a Python interpreter, a shell is started to run a command which starts another Python interpreter that is supposed to print the CONFPATH environment variable. This inner Python code fails, however, raising a KeyError exception on not finding CONFPATH in its environment. This is in contrast to the shell's behaviour which was to simply show an empty value. Since the exception was not caught, a traceback was printed and the Python shell returned an error code, in turn returned by the subshell, and finally printed by our outer Python interpreter as 256.

You have shown commands run from two distinct environments: a shell in which CONFPATH is set, and a Python interpreter in which it is not. pstree, ps f or ps -H might help you visualize the process tree and thus where the environment was inherited from. Note that the environment is copied from the parent process; changing it in a parent will only affect new children, not existing ones.

In Linux it is also possible to find the environment in the /proc filesystem. For instance, tr \\0 \\n < /proc/$$/environ prints the environment of the shell it's run from (the shell expands $$ into its own process ID).

This distinction becomes more important as you run things from different environments; for instance, anything set through your .profile or .bashrc files won't affect commands run from cron, and similarly with system startup scripts. Most programs leave the environment as is but some make specific exceptions, such as setuid programs ignoring LD_LIBRARY_PATH, or su and env rewriting the environment.




回答2:


Try exporting the shell variable from the parent shell, i.e. the shell in which you start Python:

$ CONFPATH=/home/claramart/Datamart/Parameter
$ echo $CONFPATH
/home/claramart/Datamart/Parameter
$ env | grep CONFPATH
$ python3 -c 'import os; print(os.environ["CONFPATH"])'
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib64/python3.5/os.py", line 725, in __getitem__
    raise KeyError(key) from None
KeyError: 'CONFPATH'
$ python3 -c 'import os; print(os.system("echo $CONFPATH"))'

0

# Try the same after exporting the variable
$ export CONFPATH
$ env | grep CONFPATH
CONFPATH=/home/claramart/Datamart/Parameter
$ python3 -c 'import os; print(os.environ["CONFPATH"])'
/home/claramart/Datamart/Parameter
$ python3 -c 'import os; print(os.system("echo $CONFPATH"))'
/home/claramart/Datamart/Parameter
0

Shell variables are not exported by default so, prior to the export command above, CONFPATH is not actually exported by the parent process (your terminal's shell). As shown above, your Python process should not have CONFPATH defined in its environment at all.

Having said that I am surprised to see that looking up the environment variable in os.environ apparently works for you whilst os.system() does not. Either both should work, or neither should work, depending on the availability of the environment variable. Perhaps it is a quirk of using Pyzo or with the way that you (or Pyzo) invoke the interpreter.



来源:https://stackoverflow.com/questions/45346999/how-does-os-system-differ-from-command-line

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!