I want to run a program from my Python script.
In cmd
, I would do this:
cd C:\Program Files (x86)\Tools\Converter
Converter.exe -i "C:\Temp\20220902-0001.csv" -o "C:\Temp\20220902-0001.mf4" -f --p-filetype Csv --p-rowsignalnames 1 --p-rowsignalunits 2 --p-rowdatabegin 4 --p-csvseparator Semicolon --p-mastersignalnames Time;
I tried this code to emulate that from my script:
import subprocess
convvers = subprocess.Popen(['Converter.exe', '-i r"C:\\Temp\\20220902-0001.csv" -o r"C:\\Temp\\20220902-0001.mf4"'], shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd="C:\\Program Files (x86)\\Tools\\Converter")
but I got an error:
ERROR(S):
Required option 'o, output-file' is missing.
What is wrong? How do I fix it?
CodePudding user response:
Either allow the shell to split up the arguments, or do it yourself. Mixing and matching won't turn out well. Furthermore, by writing something like 'foo r"bar"'
, you put the actual letter r
and the double-quotes into the string; keep in mind that this syntax is only meaningful in the Python code itself, not at the command line.
Using the shell (not recommended except where necessary), pass a single string with the command as you would type it in the terminal:
subprocess.Popen(
r'Converter.exe -i C:\Temp\20220902-0001.csv -o C:\Temp\20220902-0001.mf4',
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
cwd=r'C:\Program Files (x86)\Tools\Converter'
)
Notice I used raw strings to avoid doubling up the backslashes. Keep in mind that the string literal will be processed twice: first by Python to determine what is actually in the string that makes up the command line, and then by the shell to split it into individual tokens (i.e., what would be sys.argv
if you were calling another Python script).
This is important for portability: the Windows shell will expect \
to be part of a file path, but Linux and Mac will treat it as an escape character. On those systems, if you needed to include \
in an argument for some reason (unusual, since it isn't a path separator there), you would have to double it up even when using a raw string. On the other hand, on those systems you can use \
to escape spaces in file names instead of quoting the name.
Different shells also have their own rules for how quoting works.
Note well that, for example, the -i
and the C:\Temp\20220902-0001.csv
will be separate arguments. This is by design, and what the program expects.
Doing the tokenization yourself (recommended):
subprocess.Popen(
[
'Converter.exe', '-i', r'C:\Temp\20220902-0001.csv',
'-o', r'C:\Temp\20220902-0001.mf4',
],
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
cwd=r'C:\Program Files (x86)\Tools\Converter'
)
Each element of the list will be an argument; we don't do any escaping or quoting to help out the shell, because the shell doesn't examine the arguments - they are passed directly.
Please also read Windows path in Python. It is normally not necessary to use backslashes (or worry about the problems they cause) for Windows paths, even at the command line. It is extremely likely that the code will work fine using forward slashes in the path instead:
subprocess.Popen(
[
'Converter.exe', '-i', 'C:/Temp/20220902-0001.csv',
'-o', 'C:/Temp/20220902-0001.mf4',
],
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
cwd='C:/Program Files (x86)/Tools/Converter'
)
CodePudding user response:
Try removing the r
before your parameters in the command in -i r"C:\Temp\20220902-0001.csv
Once you are in the string that you started with '
, there is no python syntax anymore, so the r""
will not make the string a raw string as in python.
Thus, try:
convvers = subprocess.Popen(['Converter.exe', '-i "C:\Temp\20220902-0001.csv" -o "C:\Temp\20220902-0001.mf4"'], shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd="C:\Program Files (x86)\Tools\Converter")