Reputation: 19
Apologies in advance - I'm very new to Python and the subprocess documentation goes way over my head!
I have a windows executable that converts a proprietary file type to a Geotiff. When I run the executable, it prompts me to put in the file name I'd like to use, and then gives me several options in turn - what would I like to do (option 6), what output file type (option 3) etc., finally ending with asking me for an output file name. I have about 2,000 images to convert, so I'd like to automate this process.
I've tried several variations on
subprocess.Popen('executable, input file, arguments, outputfile')
or
prog = subprocess.call('executable',stdout=PIPE,stdin=PIPE,stederr=PIPE)
out, err = prog.communicate('filename\narguments\noutputfile')
or
result = subprocess.check_output(['executable','inputfile','arguments','outputfile')
Following suggestions from other questions on this site. None of them give me errors, but they cause the file to just sit there running and doing nothing. What commands should I use to run my executable file with the correct arguments and save the output Geotiff generated by the Windows executable?
Thanks!
Upvotes: 1
Views: 3117
Reputation: 34270
Usually a command-line utility can receive its parameters as command-line arguments, but sir_util2 instead reads user input from stdin
via the C runtime function fscanf
1. The subprocess convenience functions call
, check_call
, and check_output
don't make it easy to send input to stdin
. Use the Popen
class directly and then communicate
.
I manually traced the fscanf
calls in the source file sir_util2.c to come up with the following:
import subprocess
sir_util2_path = 'sir_util2.exe'
def sir_to_geotiff(infname, outfname, smin, smax, show_nodata):
show_nodata = int(show_nodata)
opt = 6 # convert to image
fmt = 3 # GeoTIFF
param = [infname, opt, fmt, smin, smax, show_nodata, outfname]
cmd = [sir_util2_path]
p = subprocess.Popen(cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
out, err = p.communicate('\n'.join(map(str, param)))
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode,
cmd,
output=(out,err))
I used a little test program instead of compiling the original source, so YMMV with the actual program.
#include <stdio.h>
int main()
{
int num;
float fnum;
char str[250];
fscanf(stdin, "%s", str);
printf("input filename: %s\n", str);
fscanf(stdin, "%d", &num);
printf("menu option: %d\n", num);
fscanf(stdin, "%d", &num);
printf("output format: %d\n", num);
fscanf(stdin, "%f", &fnum);
printf("min saturation: %f\n", fnum);
fscanf(stdin, "%f", &fnum);
printf("max saturation: %f\n", fnum);
fscanf(stdin, "%d", &num);
printf("show no-data: %d\n", num);
fscanf(stdin, "%s", str);
printf("output filename: %s\n", str);
return 1; /* force error */
}
I forced it to exit with a non-zero return code. This lets me check the CalledProcessError
:
try:
sir_to_geotiff('example.sir',
'example.tif',
30.0,
80.0,
True)
except subprocess.CalledProcessError as e:
print(e.output[0])
Output:
input filename: example.sir
menu option: 6
output format: 3
min saturation: 30.000000
max saturation: 80.000000
show no-data: 1
output filename: example.tif
1. As was noted in a comment by J.F. Sebastian, a program could, but thankfully this one does not, read from the console input buffer directly via ReadConsoleInput
, which is called by the CRT _getch
function.
Upvotes: 2
Reputation: 316
You could simply use os.system. Here's an example
from os import system
system("Path\to\Application.exe input file arguments outputfile")
This is from Python 2.7, but should work in 3.x.
Upvotes: 0