space in python subprocess.Popen() arguments - python

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.

Related

Executing a shell script with arguments from a python script

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)

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'])

Python - Execute program with parameters with file output

I am trying to use Python to run an executable (Windows 7) with parameters. I have been able to make the program run, but the amount of parameters I can use that will prove the Python script worked with parameters is limited. The best one is formatted like so:
-debugoutput debug.txt
I have tested this using a windows shortcut with an edited target and it works, it creates a debug output in the program directory.
Here is the code I am using:
import subprocess
args = [r"C:\Users\MyName\LevelEditor\LevelEditor.exe", "-debugoutput debug.txt"]
subprocess.call(args)
This does run the program, but the debug output is not created. I have tried putting an "r" in front of the parameter but this made no difference. I assume it is a simple formatting error but I can't find any examples to learn from that are doing the same thing.
UPDATE:
Thanks for the answers everyone, all the same, simple formatting error indeed.
In-code definition results in invocation of shell command line:
C:\Users\MyName\LevelEditor\LevelEditor.exe "-debugoutput debug.txt"
As you can see, by merging -debugoutput debug.txt to single list element, you explicitly stated that space between them shouldn't be parsed as command line argument separator.
To achieve expected behavior put file name string as separate element to argument list.
[r"C:\Users\MyName\LevelEditor\LevelEditor.exe", "-debugoutput", "debug.txt"]
As far as I know you need to split the arguments by the space, so your args would look like:
args = [r"C:\Users\MyName\LevelEditor\LevelEditor.exe", "-debugoutput", "debug.txt"]
Does that work?
I do not know if it works, but
import subprocess
args = [r"C:\Users\MyName\LevelEditor\LevelEditor.exe", "-debugoutput", "debug.txt"]
subprocess.run(args)
Following the docs

Difference between os.execl() and os.execv() in python

Is there a difference between os.execl() and os.execv() in python? I was using
os.execl(python, python, *sys.argv)
to restart my script (from here). But it seems to start from where the previous script left.
I want the script to start from the beginning when it restarts. Will this
os.execv(__file__,sys.argv)
do the job? command and idea from here. I couldn't find difference between them from the python help/documentation. Is there a way do clean restart?
For a little more background on what I am trying to do please see my other question
At the low level they do the same thing: they replace the running process image with a new process.
The only difference between execv and execl is the way they take arguments. execv expects a single list of arguments (the first of which should be the name of the executable), while execl expects a variable list of arguments.
Thus, in essence, execv(file, args) is exactly equivalent to execl(file, *args).
Note that sys.argv[0] is already the script name. However, this is the script name as passed into Python, and may not be the actual script name that the program is running under. To be correct and safe, your argument list passed to exec* should be
['python', __file__] + sys.argv[1:]
I have just tested a restart script with the following:
os.execl(sys.executable, 'python', __file__, *sys.argv[1:])
and this works fine. Be sure you're not ignoring or silently catching any errors from execl - if it fails to execute, you'll end up "continuing where you left off".
According to the Python documentation there's no real functional difference between execv and execl:
The “l” and “v” variants of the exec* functions differ in how command-line arguments are passed. The “l” variants are perhaps the easiest to work with if the number of parameters is fixed when the code is written; the individual parameters simply become additional parameters to the execl*() functions. The “v” variants are good when the number of parameters is variable, with the arguments being passed in a list or tuple as the args parameter. In either case, the arguments to the child process should start with the name of the command being run, but this is not enforced.
No idea why one seems to restart the script where it left off but I'd guess that that is unrelated.

run python command line arguments in shell script

I have a script which takes in few arguments
./hal --runtest=example
where example = /home/user/example.py
how can I pass these arguments in shell script?
I'm having trouble figuring out what you're asking, but assuming your question is "How can a shell script pass dynamic arguments to a command that happens to be written in Python" and you are using a Bourne-family shell (very likely), the simplest correct answer would be
example=/home/user/example.py
./hal "--runtest=$example"
The shell will resolve the quoting and the script will see --runtest=/home/user/example.py without breaking if you later decide to pass in a path containing spaces.
Take a look a the following:
http://lowfatlinux.com/linux-script-variables.html
It is Bash specific though and as per comments above not sure which shell you're using.
Here you'll find all you need in terms of how to pass an argument to a shell script.

Categories