简体   繁体   中英

Python: how to execute shell command and do something when the process starts waiting for input

I have a console utility written in java which checks some remote data, outputs possible options to the user, and then waits for user input to choose one of the options. The utility uses command line arguments to determine which data to check and what to show to the user. I want to see output of running this utility multiple times with different arguments to find an optimal solution. If I do it manually my workflow looks something like this

./command arg1 arg2
*waits several seconds for the output
*analyses output
*if found the desired option chooses it by typing its value
*else presses ^C and carries on searching
./command args2 arg1
*...
./command arg1 arg3
*...

It is annoying to do manually, it is problematic to change source code of the utility, therefore I want to automate it using Python

I found there are several options to execute a shell command and capture its output, but I cannot find how to register callback for to capture the moment when shell command starts waiting for user input

He are my intentions in code

import itertools

some_args = ['ARG1', 'ARG2', 'ARG3']

def execute(comb):
    # execute ./command comb[0] comb[1]
    # is it possible to have something like this?
    # register_on_input_waiting(do_something_with_output)
    pass

def do_something_with_output(output):
     # TODO: gather all the output, analyze it in code, and present best option to the user
     pass

for comb in itertools.combinations(some_args, 2):
     comb_rev = comb[::-1]
     execute(comb)
     execute(comb_rev)

Actually I found a way, how to check, if a program waits for input. However, it is not plattform compactible and in my opinion this is more hacking, than engineering.

On a X86 64 Linux system I can run:

gdb <my_program>
(gdb) catch syscall read
(gdb) command 1
 >if $rdi != 0
  >continue
  >end
 >end
(gdb) run

Now gdb will interrupt the program everytime, it tries to read from stdin. I am pretty sure, that there are python interfaces to gdb.

Note, that is works on X86 64 Architecture and on Linux. Other operating systems may have different system calls and $rdi is architecture specific.

If your program is interactive, the best way to automate it, is using pexpect (pythons expect implementation). You then start your process with:

p = pexpect.spawn("...")

If you know the questions, the program asks, you can filter for them:

pat = [ "Please enter (.+): ", ...]

ind = p.expect(pat)
if ind == 0:
  print("User asked for " + p.match.group(1))

In general, it's not possible to find the moment, when the program expects input.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM