Karen
Karen

Reputation: 19

How do you call a windows .exe file from Python, enter parameters, and get a file output?

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

Answers (2)

Eryk Sun
Eryk Sun

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 fscanf1. The subprocess convenience functions call, check_call, and check_outputdon'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

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

Related Questions