0

I'm new to Python and could not find a solution for the following propblem:

I want to write python script, which let's say opens the cmd and executes several commands in a for loop. Starting the cmd (e.g. subprocess.run())and predefining the command happens with Python (v.3.6).

import subprocess
_path = "C:\\..."
_exe = "...\\cmd.exe"
subprocess.run(_path + _exe)
for i in range (1,100,1)
   ...

But how can I then write the command from Python into cmd? And in consequence? How can i get a signal, whether my cmd command is executed so i can start a new command (like in a for loop)

Thanks for the help and with best regards,

Andreas Buyer

a.buyer
  • 3
  • 1
  • Use a pipe for standard input? – iBug Feb 18 '18 at 06:26
  • you could run commands directly without `cmd.exe`: `for cmd in commands: subprocess.run(cmd)`. Or you could generate a bat-file and run it: `subprocess.run(batfile)` if the commands depend on `cmd.exe`. To open a new console window: `cmd /c start your_command` [How can I open two consoles from a single script](https://stackoverflow.com/q/19479504/4279) – jfs Feb 18 '18 at 06:50

1 Answers1

0

You probably wanna use Popen.communicate(input=None, timeout=None) and set the shell arg to true. Then you wanna wait on the process output stream for the response to your command. Note: Popen.communicate requires the input to be byte-encoded. The output of Popen.communicate is also byte encoded, so you need to do a str.decode() on it to extract the encoded strings.

All of this is fully documented in the Python API. I would suggest you read the manual.

Or, you could use a library like this one which wraps all of this stuff for you.

import subprocess

proc = subprocess.Popen('ls', stdout=subprocess.PIPE, stdin=subprocess.PIPE)
try:
    outs, errs = proc.communicate(timeout=15) # use input= param if you need to
    proc.wait()
except TimeoutExpired:
    proc.kill()
    outs, errs = proc.communicate()

print ('%s, %s' % (outs, errs))

Output and comparison to actual 'ls' output:

$ python popen_ex.py 
b'__pycache__\npopen_ex.py\n', None
$ ls
__pycache__ popen_ex.py

Any additional commands you need to send to popen can be sent in proc.communicate.

If you REALLY want to communicate to an interactive shell, Popen.communicate() allows for a ONE TIME write to stdin and read from stdout/stderr. After one call to Popen.communicate(), the input/output/error streams are closed by subprocess. IF YOU WANT A FULLY INTERACTIVE SHELL, you MUST either write one yourself, or use a library, like the one I linked.

import subprocess
proc = subprocess.Popen('sh', stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
try:
    outs, errs = proc.communicate(input='ls'.encode('ascii'), timeout=15)
    proc.wait()
    print ('%s, %s' % (outs, errs))

    proc = subprocess.Popen('sh', stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
    outs, errs = proc.communicate(input='ps'.encode('ascii'), timeout=15)
    proc.wait()
    print ('%s, %s' % (outs, errs))
except TimeoutError:
    proc.kill()
    outs, errs = proc.communicate()

Output and comparison to actual 'ls', 'ps'

$ python popen_ex.py 
    b'__pycache__\npopen_ex.py\n', b''
    b'  PID TTY           TIME CMD\n  879 ttys000    0:00.18 -bash\n 7063 ttys000    0:00.06 python popen_ex.py\n 7066 ttys000    0:00.00 sh\n  911 ttys001    0:00.06 -bash\n  938 ttys002    0:00.16 -bash\n 6728 ttys002    0:00.11 python\n  972 ttys004    0:00.06 -bash\n 1019 ttys005    0:00.06 -bash\n 1021 ttys006    0:00.06 -bash\n 1023 ttys007    0:00.06 -bash\n', b''
$ ls
    __pycache__ popen_ex.py
$ ps
      PID TTY           TIME CMD
      879 ttys000    0:00.19 -bash
      911 ttys001    0:00.06 -bash
      938 ttys002    0:00.16 -bash
     6728 ttys002    0:00.11 python
      972 ttys004    0:00.06 -bash
     1019 ttys005    0:00.06 -bash
     1021 ttys006    0:00.06 -bash
     1023 ttys007    0:00.06 -bash
TTT
  • 1,952
  • 18
  • 33
  • Hi, thanks for the suggestion with Popen.communicate(). Unfortunatelly, I'm really new to Python and don't know how to implement the command (the docmentation here is rather cryptic for a newbe). Could you give a short example of how to implement the statements with an example snytax? However, as far as I recognized, it does not solve the problem with the missing signal if the command is executed in the cmd. I wrote a batch file and executed the batch file in the above mentioned loop, but insted of wainting until one loop is executed, it opened all statements simultaneously. – a.buyer Mar 01 '18 at 16:22
  • @a.buyer as stated before by jfs, there is no need to execute the command in 'cmd'. Popen supports opening a process with an **interactive shell** which is the same as launching the process in 'cmd'. I'll edit with a suggestion for how you'd do this. Now, if you're trying to write your own shell, calling command prompt is the wrong way to do it. – TTT Mar 01 '18 at 16:24
  • Hi, thanks for the help! As I said, the documentation is rather cryptic when you are a newbe to python ;) And I needed an example implementation of how the syntax looks like. Now it works =) – a.buyer Mar 06 '18 at 07:32