Python: on linux, subprocess.Popen() works weird with shell = True - python

If I execute following python code on Windows:
import subprocess
subprocess.Popen( [ 'python', 'foo' ], shell = True ).communicate()
I got error written into stdout, as expected:
python: can't open file 'foo': [Errno 2] No such file or directory
But if i execute same code on linux (ubuntu, OSX - any) I got interactive python REPL started instead of this text! Like this:
user#debian:~/Documents$ python test.py
Python 2.7.3 (default, Jab 2 2013, 16:53:07)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information
>>>
Why such strange behaviour? executing python interpreter with argument ('foo') must put it into evaluation mode on all platforms, not into REPL mode.

This is spelled out in the documentation:
The shell argument (which defaults to False) specifies whether to use the shell as the program to execute. If shell is True, it is recommended to pass args as a string rather than as a sequence.
On Unix with shell=True, the shell defaults to /bin/sh. If args is a string, the string specifies the command to execute through the shell. This means that the string must be formatted exactly as it would be when typed at the shell prompt. This includes, for example, quoting or backslash escaping filenames with spaces in them. If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself.
(emphasis mine)

Related

Starting a python shell with arguments

is it possible to pass arguments to the python in linux without having a file? I'm currently not able to create a file or change permissions and I don't want to write it inside my code like this:
import sys
sys.argv = ["arg1", "arg2", ...]
I'd like to hand over the arguments while I'm starting the shell:
python <arguments>
While is is questionable if passing commands line arguments to an interactive shell is best practice, it is indeed possible by passing - instead of the the scripts file name:
$ python - a1 a2
Python 2.7.14 (default, Sep 23 2017, 22:06:14)
[GCC 7.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.argv
['-', 'a1', 'a2']
If you are using IPython as interactive shell, you can pass arguments to scripts you run using the %run magic command:
In [1]: %run myscript.py arg1 arg2 ...
(It's not really clear to me what you are trying to achieve, but you probably want to pass the arguments to some script.)

How do I get the shell variable value in Popen

I'm trying to pass some secrets to shell commands using environment variables. The Popen seems using "single quote concept" to escape the arguments so the commands cannot get the variable value.
Python 2.7.1 (r271:86832, Mar 3 2017, 10:25:58)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux3
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> subprocess.Popen(['echo','$PATH'])
$PATH
Expected output is the real $PATH values like "/bin:/sbin:/usr/bin..."
Thanks!
You need a shell to evaluate your line:
subprocess.Popen('echo $PATH', shell=True)
But if this is all you want then consider this:
print os.getenv('PATH')
Use shell=True, but be careful https://docs.python.org/3/library/subprocess.html#security-considerations
subprocess.Popen('echo $PATH', shell=True)
Using shell is dangerous if the command line is filed from external sources, so use it with caution.
Also, there is an optional parameter to decide where the shell should be when launching the command.
command = 'echo $PATH'
p = subprocess.Popen(command, shell=True, cwd='./')
p.communicate() # it would wait until the subprocess is complete.

Writing Python script in PowerShell: how to use argv?

I'm a beginner to Python. I've already tried to search for the answer to this question for a long time but had no luck with that. Anyhow here's the code that I want to run (I saved it as test.py):
from sys import argv
script, firstArgument = argv
print "Hello %s!" %firstArgument
It works perfectly fine if I type this into PowerShell:
>> cd ~
>> Python test.py "StackOverflow"
However if I try to type the code into PowerShell like this:
>> cd ~
>> Python
>> from sys import argv
>> script, firstArgument = argv
I get a huge error at that point... I'm just wondering, is there a way to declare argv directly into the PowerShell or is it just not possible?
-Thanks
When you invoke python on its own to get it into interactive mode, there are no arguments passed in. Therefore, argv is empty.
I'm running on Ubuntu, but it's the same general concept in Windows:
:~ $ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from sys import argv
>>> print argv
>>> ['']
Powershell and Python are two separate things, each with their own concepts of the arguments passed to them. Just as a bash script has the concept of passed-in arguments, so too does Powershell, though they are handled differently. However, neither is directly connected to Python's argv.
In general, one can use environment variables to pass things back and forth between Python and the shell (i.e. you could set environment variables inside of Python that could be read in the shell or vice versa, but in either case, these would be different from argv, which is specifically the arguments passed in to the python executable). Or one could use environment variables from the shell to determine what arguments should be passed to python, thereby determining what argv will be.
See this link for more detail: https://docs.python.org/2/library/sys.html#sys.argv
Edit in response to comment from OP:
You can't declare argv, per se. It's representative of how the interpreter was invoked, and in interactive mode, by definition, it has no arguments.
For your specific example, it has to do with the way tuples are unpacked in Python and the current state of argv, which is empty string.
:~ $ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from sys import argv
>>> firstArgument=argv
>>> print firstArgument
['']
>>> firstArgument, secondArgument=argv
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: need more than 1 value to unpack
Since argv only has one element in it, you can't assign it to two variables.
You could, for example, do this:
>>> firstArgument, secondArgument=argv,1
>>> print secondArgument
1
Now there actually are two values -- the tuple ('', 1), and so it can be unpacked into the two different variables.

Can python shell have some pre-input?

When testing in python shell, I always have to type some import like:
Python 2.5.4 (r254:67916, Jun 24 2010, 15:23:27)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>import sys
>>>import datetime
Can someone help me to automatically finish these? It means I run some command to enter python shell it has already done import for me, and a python shell waiting for me to continue type command.
Thanks.
Try:
python -i -c "import sys; import datetime;"
More info:
-i : inspect interactively after running script; forces a prompt even
if stdin does not appear to be a terminal; also PYTHONINSPECT=x
&
-c cmd : program passed in as string (terminates option list)
Create a file with the commands you want to execute during startup, and set the environment variable PYTHONSTARTUP to the location of that file. The interactive interpreter will then load and execute that file. See http://docs.python.org/tutorial/interpreter.html#the-interactive-startup-file
On a sidenote, you might want to consider ipython as an improved Python shell when working in interactive mode.

os.system() execute command under which linux shell?

I am using /bin/tcsh as my default shell.
However, the tcsh style command os.system('setenv VAR val') doesn't work for me. But os.system('export VAR=val') works.
So my question is how can I know the os.system() run command under which shell?
Was just reading Executing BASH from Python, then 17.1. subprocess — Subprocess management — Python v2.7.3 documentation, and I saw the executable argument; and it seems to work:
$ python
Python 2.7.1+ (r271:86832, Sep 27 2012, 21:16:52)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> print os.popen("echo $0").read()
sh
>>> import subprocess
>>> print subprocess.call("echo $0", shell=True).read()
/bin/sh
>>> print subprocess.Popen("echo $0", stdout=subprocess.PIPE, shell=True).stdout.read()
/bin/sh
>>> print subprocess.Popen("echo $0", stdout=subprocess.PIPE, shell=True, executable="/bin/bash").stdout.read()
/bin/bash
>>> print subprocess.Popen("cat <(echo TEST)", stdout=subprocess.PIPE, shell=True).stdout.read()
/bin/sh: Syntax error: "(" unexpected
>>> print subprocess.Popen("cat <(echo TEST)", stdout=subprocess.PIPE, shell=True, executable="/bin/bash").stdout.read()
TEST
Hope this helps someone,
Cheers!
These days you should be using the Subprocess module instead of os.system(). According to the documentation there, the default shell is /bin/sh. I believe that os.system() works the same way.
Edit: I should also mention that the subprocess module allows you to set the environment available to the executing process through the env parameter.
os.system() just calls the system() system call ("man 3 system"). On most *nixes this means you get /bin/sh.
Note that export VAR=val is technically not standard syntax (though bash understands it, and I think ksh does too). It will not work on systems where /bin/sh is actually the Bourne shell. On those systems you need to export and set as separate commands. (This will work with bash too.)
If your command is a shell file, and the file is executable, and the file begins with "#!", you can pick your shell.
#!/bin/zsh
Do Some Stuff
You can write this file and then execute it with subprocess.Popen(filename,shell=True) and you'll be able to use any shell you want.
Also, be sure to read this about os.system and subprocess.Popen.

Categories