Executing a shell script with arguments from a python script - python

My Shell script is executed like this from the command line
./pro.sh "Argument1"
I am calling it from my python script currently like this
subprocess.call(shlex.split('bash pro.sh "Argument1"'))
How do I pass the value of Argument1 as a variable. My argument to the script can be any string. How do I achieve this?

You can use
subprocess.Popen(["bash", "pro.sh", "Argument1"])
If your string argument is multiple words, it should work fine.
subprocess.Popen(["bash", "pro.sh", "Argument with multiple words"])
As long as the multiple words are in one string in the list passed to subprocess.Popen(), it is considered one argument in the argument list for the command.
You should not use shell=True unless you have a good reason. It can be a security problem if you aren't very careful how it is used.

use subprocess to call your shell script
subprocess.Popen(['run.sh %s %s' % (var1, var2)], shell = True)

Related

Passing variable to shell from python

I want to pass variable from python to shell script. My code looks like below.
Object_Id=12
Class_Name='My_Class'
Folder_Path='/My_Folder'
output=subprocess.check_output(['./execute.sh, 'Object_Id', 'Class_Name', "shell=True"])
print(output)
The execute.sh script is just simple echo statement
echo $1
echo $2
the output is
Object_Id
Class_Name
The script is getting the args as literal strings but I want to get the value of the variable instead.
Your check_output call needs to pass the command and its arguments as a list or str separate from arguments to the check_output API itself. You shouldn't pass the names of your variables (your command has no idea what Object_Id means after all, and couldn't reach back into the Python process to identify if even if it understood), but rather the variables themselves (and your quotes are mismatched and need fixing). Really, you don't need shell=True here at all, so you can just do:
output = subprocess.check_output(['./execute.sh', str(Object_Id), Class_Name])
If shell=True is important for some reason, you can do it by passing the string representing the shell command:
import shlex
output = subprocess.check_output('./execute.sh {} {}'.format(shlex.quote(Object_Id), shlex.quote(Class_Name)),
shell=True)
Note that shell=True is a separate argument to check_output, not part of the command itself (the first positional argument).
it looks like it's taking the args as strings instead of the variable because you are enclosing it with '' removing them should fix it

Executing a PowerShell script OUTSIDE of Python

I am trying to run a sort of application that utilises both Python and powershell scripts. I already wrote the Python script and powershell script, which are meant to work simultaneously but separate from each other. What I want to do is create a Python program that launches them both, is there a way? Thanks!
What I have right now, as part of a larger script, is:
import subprocess
autom = r"C:\Users\mrmostacho\Desktop\Robot\Autom.ps1","-ExecutionPolicy","Unrestricted"
powershell = r"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
subprocess.Popen("%s %s" % (powershell, autom,))
I think you don't want "-ExecutionPolicy","Unrestricted" as script arguments but instead want to set powershells execution policy to allow the execution of your script. Therefore you should pass those parameters before the actual Script.
Second: It's not enough, to pass the script as argument to powershell.exe (this way the script name is interpreted as Powershell command and one has to escape the name according to powershells quoting rules). Instead the Script name should be given after the -File parameter. From online documentation:
-File []
Runs the specified script in the local scope ("dot-sourced"), so that the functions and variables that the script creates are
available in the current session. Enter the script file path and any
parameters. File must be the last parameter in the command, because
all characters typed after the File parameter name are interpreted as
the script file path followed by the script parameters.
You can include the parameters of a script, and parameter values, in
the value of the File parameter. For example: -File .\Get-Script.ps1 -Domain Central
Typically, the switch parameters of a script are either included or
omitted. For example, the following command uses the All parameter of
the Get-Script.ps1 script file: -File .\Get-Script.ps1 -All
In rare cases, you might need to provide a Boolean value for a switch
parameter. To provide a Boolean value for a switch parameter in the
value of the File parameter, enclose the parameter name and value in
curly braces, such as the following: -File .\Get-Script.ps1 {-All:$False}.
Third: As cdarke already commented, it's better to use a list instead of a string as argument to Popen. This way one doesn't need to worry about the CommandLine parsing on Windows.
Altogether, this should be the way to go. (Tested with small test script.)
import subprocess
autom = r"C:\Users\mrmostacho\Desktop\Robot\Autom.ps1"
powershell = r"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
subprocess.Popen([powershell,"-ExecutionPolicy","Unrestricted","-File", autom])
If you need to pass arguments to the script, do it like this:
subprocess.Popen([powershell,"-ExecutionPolicy","Unrestricted","-File", autom, 'arg 1', 'arg 2'])

Using variables as arguments for a command called by subprocess in Python 2.7.x

I'm trying to create a basic function that will pass a filename and arguments to a program using call() from the subprocess module. The filename and arguments are variables. When I use call() it takes the variables but the called program reads their strings with " included.
Here's the code in question:
from subprocess import call
def mednafen():
print "Loading "+romname+"..."
call(["mednafen", args, romname])
print "Mednafen closed."
romname="kirby.zip"
args="-fs 1"
mednafen()
I expected this would execute
mednafen -fs 1 kirby.zip
but instead it appears to interpret the variable's strings as this:
mednafen "-fs 1" "kirby.zip"
Because of this, mednafen isn't able to run because it can't parse an argument that starts with ".
It works as expected if I use shell=True but that feature is apparently strongly discouraged because it's easy to exploit?
call("mednafen "+ args +" "+romname+"; exit", shell=True)
Is there a way to do this without using the shell=True format?
Well, yes. That's exactly what the documentation says it does. Create and pass a list containing the command and all arguments instead.
EDIT: The solution suggested by Jonas Wielicki is to make sure every single string that would normally be separated by spaces in shell syntax is listed as a separate item; That way call() will read them properly. shlex is unnecessary.
args = ["-fs", "1"]
call(['mednafen']+args+[rom])
My initial (less concise) solution:
shlex.split() takes the variables/strings I feed it and converts them into a list of string literals, which in turn causes the called command to parse them correctly rather than interpreting the variables as strings within quotes.
So instead of the argument being treated like "-fs 0" I'm getting -fs 0 like I originally wanted.
import shlex
call(shlex.split("mednafen "+args+" "+romname))

How to use subprocess to fire and forget in python 2.7

I need to execute a command line in the bakground in python 2.7. I need to fire and forget.
Here is the command:
cmd = "/usr/local/bin/fab -H %s aws_bootstrap initial_chef_run:%s,%s,%s -w" % (...)
How do I use the subproccess module?
e.g. is it
subprocess.call([cmd])
or
subprocess.call(["/usr/local/bin/fab", "-H %s aws_bootstrap initial_chef_run:%s,%s,%s -w"])
I dont get how to use the list. Or is every element of the list what would be a white space.
Thanks
each thing that would be seperated by whitespace is a seperate entity of the list
subprocess.call is blocking however
subprocess.popen is non-blocking
cmd = ["/usr/local/bin/fab", "-H",var1,"aws_bootstrap initial_chef_run:%s,%s,%s"%(var2,var3,var4), "-w"]
subprocess.popen(cmd) # dopnt wait just keep going
#or
subprocess.call(cmd) # wait until the command returns
you may however alternatively pass the command as one big string
cmd = "/usr/local/bin/fab -H %s aws_bootstrap initial_chef_run:%s,%s,%s -w" % (...)
subprocess.call(cmd)
in general this method(passing a single string) is frowned upon for some reason that has never been explained sufficiently to me
I used this recently to fire a perl script, like so:
var = "C:\Users\user\Desktop"
retcode = subprocess.call(["perl", '.\hgncDL.pl',var])
Working code
Define hParam and runParams in following code and you're good to go:
hParam = 'hParam'
runParams = (a,b,c)
args = ('/usr/local/bin/fab', '-H', hParam, 'aws_bootstrap', 'initial_chef_run:%s,%s,%s' % runParams, '-w')
subprocess.Popen(args)
Details
How do I use <any python module> module?
https://docs.python.org is a good starting point.
In particular, docs for subprocess module available here.
I can't provide direct links for each case later in this answer due to restriction imposed by low reputation. Each time I will be referring to 'docs', look for a section in docs on the module.
I need to execute a command line in the background in python 2.7. I need to fire and forget
Consider subprocess.Popen(args). Note capital 'P'.
See docs for more details.
subprocess.call(args) works in similar way, but it would block until the command completes. As stated in docs:
Run the command described by args. Wait for command to complete, then return the returncode attribute.
How to use the sequence form of args parameter?
This is covered in "Frequently used arguments" section of docs:
args is required for all calls and should be a string, or a sequence of program arguments. Providing a sequence of arguments is generally preferred, as it allows the module to take care of any required escaping and quoting of arguments (e.g. to permit spaces in file names).
Also, passing an args in a string form has its limitation:
If passing a single string, either shell must be True or else the string must simply name the program to be executed without specifying any arguments.
Despite mentioned limitation, subprocess.Popen('cmd.exe /?') works for me. Win7, Python 2.7.8 64bit.
HTH, cheers.

space in python subprocess.Popen() arguments

I try to invoke an external perl script in my python script. I used subprocess.Popen(). If run it like
subprocess.Popen([mybinary, '-arg1 argv1', '-arg2 argv2'])
the arguments are not sent to mybinary. But if I separate arguments from values, then it runs properly:
subprocess.Popen([mybinary, '-arg1', 'argv1', '-arg2', 'argv2'])
Why is it so? args needs to be a string or list. If I concatenate mybinary and the arguments into a single string for Popen(), Popen() does not work, either. I suspect it is relevant to the key-worded arguments (**kwargs). But the script invoked is external. I don't see the reason.
I try to invoke an external perl script in my python script. I used
subprocess.Popen(). If run it like
subprocess.Popen([mybinary, '-arg1 argv1', '-arg2 argv2'])
the arguments are not sent to mybinary.
I doubt that. I rather think they come along there in a non-proper way.
The script expects options and their values as two separate arguments. If they are combined, it doesn't work.
The arguments are passed in shape and count exactly as you give them in the list.

Categories