Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Subprocess or BAT script splits argument on equal sign

How do I add this: -param:abc=def as a SINGLE command line argument?

Module subprocess splits this up in TWO arguments by replacing the equal sign with a space.

Here is my python script:

import subprocess

pa=['test.bat', '--param:abc=def']
subprocess.run(pa)

Here is the test program test.bat:

@echo off
echo Test.bat
echo Arg0: %0
echo Arg1: %1
echo Arg2: %2
pause

and here the output:

Test.bat
Arg0: test.bat
Arg1: --param:abc
Arg2: def
Press any key to continue . . .

Because the equal sign is gone, the real app will not be started correctly. By the way, this problem also seems to happen when running on linux, with a sh script instead of a bat file.

I understand that removing the equal sign is a 'feature' in certain cases, e.g. with the argparse module, but in my case I need to keep the equal sign. Any help is appreciated!

like image 629
Roland Avatar asked Feb 06 '26 06:02

Roland


2 Answers

Welcome to .bat file hell

To preserve equal sign, you'll have to quote your argument (explained here Preserving "=" (equal) characters in batch file parameters) ('"--param:abc=def"'), but then subprocess will escape the quotes

Test.bat
Arg0: test.bat
Arg1: \"--param:abc=def\"
Arg2:

Good old os.system won't do that

import os

os.system('test.bat "--param:abc=def"')

result

Test.bat
Arg0: test.bat
Arg1: "--param:abc=def"
Arg2:

Damn, those quotes won't go off. Let's tweak the .bat script a little to remove them manually

@echo off
echo Test.bat
echo Arg0: %0
rem those 2 lines remove the quotes
set ARG1=%1
set ARG1=%ARG1:"=%

echo Arg1: %ARG1%
echo Arg2: %2

now it yields the proper result

Test.bat
Arg0: test.bat
Arg1: --param:abc=def
Arg2:

Alternatively, stick to subprocess and remove quotes AND backslashes.

like image 71
Jean-François Fabre Avatar answered Feb 09 '26 10:02

Jean-François Fabre


While this is indeed mainly a batch file hell problem, Python's subprocess implementation detail is also relevant here. So I'd like to add some minor things to @jean-françois-fabre's great answer.

As said above, when using a BAT file directly, you can avoid the argument being split at equal sign by quoting it. And if you don't want the quotes later when you refer to the argument, you can simply use %~1 instead of doing string replacement manually.

E.g. in Test.bat:

@echo off
echo Test.bat
echo Arg0: %0
echo Arg1: %~1
echo Arg2: %~2
pause
D:\3>Test.bat "abc=def" 
Test.bat
Arg0: Test.bat
Arg1: abc=def
Arg2:
Press any key to continue . . .

(Note that it successfully got abc=def as an argument, and by using %~1 we removed the quotes too.)

Now, this is only half of the problem. The other half is on Python's side: subprocess.run(['Test.bat', 'abc=def']) will not work because Python won't quote argument with equal sign, and there is no way to force it to do it. (You can't manually add it, Python will escape it to \".)

So you have to manually construct the whole string and either use os.system as said above, or simply pass it (the string, instead of a list) into subprocess.run() :

subprocess.run('Test.bat "abc=def"') 

Also note, never use string (instead of list) in subprocess.run() on unix-like system. It will cause issues. If you really want to, add shell=True (you can add it on Windows too).

In summary:

import subprocess
import os

subprocess.run(['Test.bat', 'abc=def']) # BAD
subprocess.run(['Test.bat', '"abc=def"']) # BAD

os.system('Test.bat "abc=def"') # OK
subprocess.run('Test.bat "abc=def"') # OK
subprocess.run('Test.bat "abc=def"', shell=True) # OK
like image 42
fireattack Avatar answered Feb 09 '26 12:02

fireattack



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!