How to handle ':' in command using os.popen - python

I am trying to call a program with:
os.popen("program -s:'*' -c:'A;B;C;'")
However, it seems that it was interpreted as shell command:
program -s '*' -c 'A;B;C;'
which result incorrect behavior.
Can somebody help me on how to hanle such situdations where ':' is inside shell commandline?

Don't use os.popen(), use the subprocess module instead:
import subprocess
result = subprocess.check_output(['program', "-s:'*'", "-c:'A;B;C;'"])
This returns the output of the program without running it through a shell, passing in the arguments directly without any additional parsing.

Related

Running python script from perl, with argument to stdin and saving stdout output

My perl script is at path:
a/perl/perlScript.pl
my python script is at path:
a/python/pythonScript.py
pythonScript.py gets an argument from stdin, and returns result to stdout. From perlScript.pl , I want to run pythonScript.py with the argument hi to stdin, and save the results in some variable. That's what I tried:
my $ret = `../python/pythonScript.py < hi`;
but I got the following error:
The system cannot find the path specified.
Can you explain the path can't be found?
The qx operator (backticks) starts a shell (sh), in which prog < input syntax expects a file named input from which it will read lines and feed them to the program prog. But you want the python script to receive on its STDIN the string hi instead, not lines of a file named hi.
One way is to directly do that, my $ret = qx(echo "hi" | python_script).
But I'd suggest to consider using modules for this. Here is a simple example with IPC::Run3
use warnings;
use strict;
use feature 'say';
use IPC::Run3;
my #cmd = ('program', 'arg1', 'arg2');
my $in = "hi";
run3 \#cmd, \$in, \my $out;
say "script's stdout: $out";
The program is the path to your script if it is executable, or perhaps python script.py. This will be run by system so the output is obtained once that completes, what is consistent with the attempt in the question. See documentation for module's operation.
This module is intended to be simple while "satisfy 99% of the need for using system, qx, and open3 [...]. For far more power and control see IPC::Run.
You're getting this error because you're using shell redirection instead of just passing an argument
../python/pythonScript.py < hi
tells your shell to read input from a file called hi in the current directory, rather than using it as an argument. What you mean to do is
my $ret = `../python/pythonScript.py hi`;
Which correctly executes your python script with the hi argument, and returns the result to the variable $ret.
The Some of the other answers assume that hi must be passed as a command line parameter to the Python script but the asker says it comes from stdin.
Thus:
my $ret = `echo "hi" | ../python/pythonScript.py`;
To launch your external script you can do
system "python ../python/pythonScript.py hi";
and then in your python script
import sys
def yourFct(a, b):
...
if __name__== "__main__":
yourFct(sys.argv[1])
you can have more informations on the python part here

Run shell script from python

I am trying to run a shell script from a python script using the following:
from subprocess import call
call(['bash run.sh'])
This gives me an error, but I can successfully run other commands like:
call(['ls'])
You should separate arguments:
call(['bash', 'run.sh'])
call(['ls','-l'])
from subprocess import call
import shlex
call(shlex.split('bash run.sh'))
You want to properly tokenize your command arguments. shlex.split() will do that for you.
Source: https://docs.python.org/2/library/subprocess.html#popen-constructor
Note shlex.split() can be useful when determining the correct
tokenization for args, especially in complex cases:
When you call call() with a list, it expects every element of that list to correspond to a command line argument.
In this case it is looking for bash run.sh as the executable with spaces and everything as a single string.
Try one of these:
call("bash run.sh".split())
call(["bash", "run.sh"])

Using Subprocess or os.system to run shell commands in python

I need to write a code in Python using functions that a friend of mine developed in shell. Is that possible? Can I do something like
output = subprocess.call('friends_developed_function', shell = True)
You need to make sure your friend's function is defined before you can call it. You cannot call a function which was defined in a parent process [Note 1]. So you could execute the following:
output = subprocess.check_output(
'source /path/to/function/definition; the_function args if needed',
shell = True)
Note that I changed subprocess.call to subprocess.check_output so that the call will return the output of the shell function, instead of its exit code.
It's a little awkward fixing the path to the script file with the function definitions. You could instead just define the function directly before calling it, using a string literal:
output = subprocess.check_output(
"""my_func() { echo The argument is "$1"; }
my_func the_argument
""",
shell = True)
Notes:
Unless you are using bash, but that probably won't work for os.system or subprocess.call(..., shell=True) because those will use the basic shell /bin/sh, which often is not bash. Even if you forced the use of bash, and you had properly exported the function definitions, it would still be a bad idea because your python script would only work if the environment were set up correctly.
There is a couple of ways to do this, I'm posting what I am familiar with.
with open(r"*file location", 'wb', 0) as file:
subprocess.check_call(*command*, stdout=file)
Now the output is in the text file location.I used check_call to validate the command so I assume subprocess.call() just executes the command.

Python Subprocess Error in using "cp"

I was trying to use subprocess calls to perform a copy operation (code below):
import subprocess
pr1 = subprocess.call(['cp','-r','./testdir1/*','./testdir2/'], shell = True)
and I got an error saying:
cp: missing file operand
Try `cp --help' for more information.
When I try with shell=False , I get
cp: cannot stat `./testdir1/*': No such file or directory
How do I get around this problem?
I'm using RedHat Linux GNOME Deskop version 2.16.0 and bash shell and Python 2.6
P.S. I read the question posted in Problems with issuing cp command with Popen in Python, and it suggested using shell = True option, which is not working for me as I mentioned :(
When using shell=True, pass a string, not a list to subprocess.call:
subprocess.call('cp -r ./testdir1/* ./testdir2/', shell=True)
The docs say:
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.
So (on Unix), when a list is passed to subprocess.Popen (or subprocess.call), the first element of the list is interpreted as the command, all the other elements in the list are interpreted as arguments for the shell. Since in your case you do not need to pass arguments to the shell, you can just pass a string as the first argument.
This is an old thread now, but I was just having the same problem.
The problem you were having with this call:
subprocess.call(['cp','-r','./testdir1/*','./testdir2/'], shell = False)
was that each of the parameters after the first one are quoted. So to the shell sees the command like this:
cp '-r' './testdir1/*' './testdir2/'
The problem with that is the wildcard character (*). The filesystem looks for a file with the literal name '*' in the testdir1 directory, which of course, is not there.
The solution is to make the call like the selected answer using the shell = True option and none of the parameters quoted.
I know that the option of shell=True may be tempting but it's always inadvisable due to security issues. Instead, you can use a combination of the subprocess and glob modules.
For Python 3.5 or higher:
import subprocess
import glob
subprocess.run(['cp', '-r'] + glob.glob('./testdir1/*') + ['./testdir2/'])
For Python 3.4 or lower:
import subprocess
import glob
subprocess.call(['cp', '-r'] + glob.glob('./testdir1/*') + ['./testdir2/'])

String parameter using subprocess module

I am using Python to simplify some commands in Maven. I have this script which calls mvn test in debug mode.
from subprocess import call
commands = []
commands.append("mvn")
commands.append("test")
commands.append("-Dmaven.surefire.debug=\"-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -Xnoagent -Djava.compiler=NONE\"")
call(commands)
The problem is with line -Dmaven.surefire.debug which accepts parameter which has to be in quotas and I don't know how to do that correctly. It looks fine when I print this list but when I run the script I get Error translating CommandLine and the debugging line is never executed.
The quotas are only required for the shell executing the command.
If you do the said call directly from the shell, you probably do
mvn test -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -Xnoagent -Djava.compiler=NONE"
With these " signs you (simply spoken) tell the shell to ignore the spaces within.
The program is called with the arguments
mvn
test
-Dmaven.surefire.debug=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -Xnoagent -Djava.compiler=NONE
so
from subprocess import call
commands = []
commands.append("mvn")
commands.append("test")
commands.append("-Dmaven.surefire.debug=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -Xnoagent -Djava.compiler=NONE")
call(commands)
should be the way to go.

Categories

Resources