Passing a Python Variable to Batch File [duplicate] - python

This question already has answers here:
Why does passing variables to subprocess.Popen not work despite passing a list of arguments?
(5 answers)
Closed 1 year ago.
I have a basic batch file that takes user input:
#echo off
set /p Thing= Type Something:
echo %Thing%
pause
However, I'd like to use a variable written in Python to pass into the batch file. Let's say just a string 'arg1' This is just a basic example, but I still cannot figure it out. The below code will run the batch process, but 'arg1' has no impact
import subprocess
filepath = r'C:\Users\MattR\Desktop\testing.bat'
subprocess.call([filepath, 'arg1'])
I have also tried p = subprocess.Popen([filepath, 'arg1']) but the batch file does not run in Python.
I have searched the web and SO, but none of the answers seem to work for me. Here are some links I've also tried: Example 1, Example 2. I've also tried others but they seem fairly specific to the user's needs.
How do I start passing Python variables into my batch files?

Your subprocess likely needs to run with a shell if you want bash to work properly
Actual meaning of 'shell=True' in subprocess
so
subprocess.Popen([filepath, 'arg1'], shell=True)
If you want to see the output too then:
item = subprocess.Popen([filepath, 'arg1'], shell=True, stdout=subprocess.PIPE)
for line in item.stdout:
print line
As a further edit here's a working example of what you're after:
sub.py:
import subprocess
import random
item = subprocess.Popen(["test.bat", str(random.randrange(0,20))] ,
shell=True, stdout=subprocess.PIPE)
for line in item.stdout:
print line
test.bat
#echo off
set arg1=%1
echo I wish I had %arg1% eggs!
running it:
c:\code>python sub.py
I wish I had 8 eggs!
c:\code>python sub.py
I wish I had 5 eggs!
c:\code>python sub.py
I wish I had 9 eggs!

Here is how I managed to call a variable from python to batch file.
First, make a python file like this:
import os
var1 = "Hello, world!"
os.putenv("VAR1", var1) #This takes the variable from python and makes it a batch one
Second, make your batch file, by going to the folder where you want your python program to work, then right-clicking in the map, then create new text file. In this text file, write whatever you want to do with the variable and make sure you call your variable using %...% like so:
echo %VAR1%
Save this file as a batch file like so: file>save as>name_of_file.bat then select: save as file: all files.
Then to call your batch file in python, write:
os.system("name_of_file.bat")
Make sure all these files are in the same map for them to work!
There you go, this worked for me, hopefully I can help some people with this comment, because I searched for so long to find how this works.
PS: I also posted on another forum, so don't be confused if you see this answer twice.

Related

Executing a profile load shell script from a python program [duplicate]

This question already has answers here:
how to "source" file into python script
(8 answers)
Closed 3 years ago.
I am struggling to execute a shell script from a Python program. The actual issue is the script is a load profile script and runs manually as :
. /path/to/file
The program can't be run as sh script as the calling programs are loading some configuration file and so must need to be run as . /path/to/file
Please do guide how can I integrate the same in my Python script? I am using subprocess.Popen command to run the script and as said the only way it works is to run as . /path/to/file and so not giving the right result.
Without knowledge of the precise reason the script needs to be sourced, this is slightly speculative.
The fundamental problem is this: How do I get a source command to take effect outside the shell script?
Let's say your sourced file does something like
export fnord="value"
This cannot (usefully) be run in a subshell (as a normally executed script would) because the environment variable and its value will be lost when the script terminates. The solution is to source (aka .) this snippet from an already running shell; then the value stays in that shell's environment until that shell terminates.
But Python is not a shell, and there is no general way for Python to execute arbitrary shell script code, short of reimplementing the shell in Python. You can reimplement a small subset of the shell's functionality with something like
with open('/path/to/file') as shell_source:
lines = shell_source.readlines()
for line in lines:
if line.strip().startswith('export '):
var, value = line[7:].strip().split('=', 1)
if value.startswith('"'):
value = value.strip('"')
elif value.startswith("'"):
value = value.strip("'")
os.environ[var] = value
with some very strict restrictions (let's not say naïve assumptions) on the allowable shell script syntax in the file. But what if the file contained something else than a series of variable assignments, or the assignment used something other than trivial quoted strings in the values? (Even the export might or might not be there. Its significance is to make the variable visible to subprocesses of the current shell; maybe that is not wanted or required? Also export variable=value is not portable; proper Bourne shell script syntax would use variable=value; export variable or one of the many variations.)
If you know what exactly your Python script needs from the shell script, maybe do something like
r = subprocess.run('. /path/to/file; printf "%s\n" "$somevariable"',
shell=True, capture_output=True, text=True)
os.environ['somevariable'] = r.stdout.split('\n')[-2]
to source the entire script in a subshell, then print to standard output the part you actually need, and capture that from your Python script (and assign it to an environment variable if that's what you eventually need to accomplish).

How to grab files generated by a subprocess?

I want to run some command line scripts from within my python program. These scripts generates some output files. I want to grab these output files from the subprocess call as object in my python program, while canceling generation of files on disk. Problem is I don't know how to do it, or whether that is even possible.
A simple example would look like this:
#foo.py
fout1 = open("temp1.txt","w")
fout2 = open("temp2.txt","w")
fout1.write("fout1")
fout2.write("fout2")
fout1.close()
fout2.close()
#test.py
import subprocess
process = subprocess.Popen(["python","foo.py"], ????????) #what arguments to use to grab temp1.txt and temp2.txt
print(process.??????) #how to access those files
I am familiar with subprocess.Popen so that is what the example code uses, but I am open to the use of other modules too if they could do it.

Execute batch file in different directory

I have a a file structure like the following (Windows):
D:\
dir_1\
batch_1.bat
dir_1a\
batch_2.bat
dir_2\
main.py
For the sake of this question, batch_1.bat simply calls batch_2.bat, and looks like:
cd dir_1a
start batch_2.bat %*
Opening batch_1.bat from a command prompt indeed opens batch_2.bat as it's supposed to, and from there on, everything is golden.
Now I want my Python file, D:\dir_2\main.py, to spawn a new process which starts batch_1.bat, which in turn should start batch_2.bat. So I figured the following Python code should work:
import subprocess
subprocess.Popen(['cd "D:/dir_1"', "start batch_1.bat"], shell=True)
This results in "The system cannot find the path specified" being printed to my Python console. (No error is raised, of course.) This is due to the first command. I get the same result even if I cut it down to:
subprocess.Popen(['cd "D:/"'], shell=True)
I also tried starting the batch file directly, like so:
subprocess.Popen("start D:/dir_1/batch_1.bat", shell=True)
For reasons that I don't entirely get, this seems to just open a windows command prompt, in dir_2.
If I forego the start part of this command, then my Python process is going to end up waiting for batch_1 to finish, which I don't want. But it does get a little further:
subprocess.Popen("D:/dir_1/batch_1.bat", shell=True)
This results in batch_1.bat successfully executing... in dir_2, the directory of the Python script, rather than the directory of batch_1.bat, which results in it not being able to find dir_1a\ and hence, batch_2.bat is not executed at all.
I am left highly confused. What am I doing wrong, and what should I be doing instead?
Your question is answered here: Python specify popen working directory via argument
In a nutshell, just pass an optional cwd argument to Popen:
subprocess.Popen(["batch_1.bat"], shell=True, cwd=r'd:\<your path>\dir1')

execute python file in batch mode by specifying the list of commands

I got a python file which is a code that I developed. During his execution I input from the keyboard several characters at different stages of the program itself. Also, during the execution, I need to close a notepad session which comes out when I execute into my program the command subprocess.call(["notepad",filename]). Having said that I would like to run this code several times with inputs which change according to the case and I was wondering if there is an automatic manner to do that. Assuming that my code is called 'mainfile.py' I tried the following command combinations:
import sys
sys.argv=['arg1']
execfile('mainfile.py')
and
import sys
import subprocess
subprocess.call([sys.executable,'mainfile.py','test'])
But it does not seem to work at least for the first argument. Also, as the second argument should be to close a notepad session, do you know how to pass this command?
Maybe have a look at this https://stackoverflow.com/a/20052978/4244387
It's not clear what you are trying to do though, I mean the result you want to accomplish seems to be just opening notepad for the sake of saving a file.
The subprocess.call() you have is the proper way to execute your script and pass it arguments.
As far as launching notepad goes, you could do something like this:
notepad = subprocess.Popen(['notepad', filename])
# do other stuff ...
notepad.terminate() # terminate running session

How to execute batch file from Python so that it could alter environment of the calling process? [duplicate]

This question already has answers here:
How to get the environment variables of a subprocess after it finishes running?
(5 answers)
Closed 9 years ago.
On Windows there's a 3rd party command line tool I would like to use in my python script. Let's say it's foobar.exe located under C:\Program Files (x86)\foobar. Foobar comes with an additional batch file init_env.bat that will set up the shell environment for foobar.exe to run.
I want to write a python script, that will first call init_env.bat once and then foobar.exe multiple times. However, all mechanisms I know of (subprocess, os.system and backticks) seem to spawn a new process for each execution. Therefore, calling init_env.bat is useless, because it does not change the environment of the process in which the python script runs and thus every subsequent call to foobar.exe fails, because it's environment is not set up.
Is it possible to call init_env.bat from python in a way that allows init_env.bat to alter the environment of the calling scripts process?
Is it possible to call init_env.bat from python in a way that allows
init_env.bat to alter the environment of the calling scripts
process?
Not easily, although, if the init_env.bat is really simple, you could attempt to parse it, and make the changes to os.environ yourself.
Otherwise it's much easier to spawn it in a sub-shell, followed by a call to set to output the new environment variables, and parse the output from that.
The following works for me...
init_env.bat
#echo off
set FOO=foo
set BAR=bar
foobar.bat
#echo off
echo FOO=%FOO%
echo BAR=%BAR%
main.py
import sys, os, subprocess
INIT_ENV_BAT = 'init_env.bat'
FOOBAR_EXE = 'foobar.bat'
def init_env():
vars = subprocess.check_output([INIT_ENV_BAT, '&&', 'set'], shell=True)
for var in vars.splitlines():
k, _, v = map(str.strip, var.strip().partition('='))
if k.startswith('?'):
continue
os.environ[k] = v
def main():
init_env()
subprocess.check_call(FOOBAR_EXE, shell=True)
subprocess.check_call(FOOBAR_EXE, shell=True)
if __name__ == '__main__':
main()
...for which python main.py outputs...
FOO=foo
BAR=bar
FOO=foo
BAR=bar
Note that I'm only using a batch file in place of your foobar.exe because I don't have a .exe file handy which can confirm the environment variables are set.
If you're using a .exe file, you can remove the shell=True clause from the lines subprocess.check_call(FOOBAR_EXE, shell=True).

Categories

Resources