Python subprocess, give an input to a child process - python

I made a program that checks a secret key. and another program that supposed to find the secret key. I managed to open a child process in the second program but couldn't send it an input. Here's the program that checks a secret key, secret_key.py:
SECRET_KEY = "hi"
current_key = 0
while not current_key == "exit":
wrong_key = False
current_key = raw_input("Enter the key or enter 'exit' to exit.\n")
for i in range(len(current_key)):
if i < len(SECRET_KEY):
if not current_key[i] == SECRET_KEY[i]:
wrong_key = True
else:
wrong_key = True
if not wrong_key:
print("the key is right!\n")
current_key = "exit"
raw_input("Press ENTER to exit\n")
exit()
Now i made a .sh file to be able to run it in a new terminal as a child process, program.sh:
#! /bin/bash
python Desktop/school/secret_key.py
And here's where i got stuck, find_key.py:
import subprocess
program = subprocess.Popen("./program.sh")
now I could't find a way to send secret_key.py the input it asks for.
Is there anyway I can send a string input to secret_key.py from find_key.py?

To send input to and read output from a process opened via Popen, you can read from and write to the process using the process' stdin and stdout fields. You do need to tell Popen to set up pipes, though:
process = subprocess.Popen([SPIM_BIN] + extra_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
pin = process.stdin
pout = process.stdout
And now you can write to pin and read from pout as you would with any old file descriptor.
Note that this will probably not allow you to connect to the gnome-terminal. But it will allow you to connect to program.sh.

Related

using subprocess.run to automate a command line application (windows 10)

trying to use python to automate a usage of a command line application called slsk-cli
manually, the procedure is straight-forward - i open a command prompt window and type 'soulseek login', then a prompt requests username, after i type in and press enter i'm requested a password.
so far, i manage to get the prompt of the username but not getting passed that.
subprocess.run('soulseek login',shell=True)
this results in the ?Login output in the python console but also the process is stuck, when i run in debug or also in run
is there a better way to go about this?
Interacting continuously with a system via subprocess can be tricky. However, it seems that your interface prompts are one after the other, which can therefore be chained together, via newline characters which act as Return key strokes.
For example, the program shown below simply prompts a user for their username and a password, to which the 'user' (your script) provides the input via the proc.communicate() method. Once these are provided, the user is asked if they'd like to continue (and do the same thing again). The following subprocess call feeds the following input into the prompter.py script:
username
password
continue reply (y or n)
Example code:
import subprocess
uid = 'Bob'
pwd = 'MyPa$$w0rd'
reply = 'n'
with subprocess.Popen('./prompter.py',
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
text=True) as proc:
stdout, stderr = proc.communicate(input='\n'.join([uid, pwd, reply]))
Output:
# Check output.
>>> print(stdout)
Please enter a username: Password: uid='Bob'
pwd='MyPa$$w0rd'
Have another go? [y|n]:
# Sanity check for errors.
>>> print(stderr)
''
Script:
For completeness, I've included the contents of the prompter.py script below.
#!/usr/bin/env python
from time import sleep
def prompter():
while True:
uid = input('\nPlease enter a username: ')
pwd = input('Password: ')
print(f'{uid=}\n{pwd=}')
sleep(2)
x = input('Have another go? [y|n]: ')
if x.lower() == 'n':
break
if __name__ == '__main__':
prompter()

How to give input to exe file using subprocess in python [duplicate]

I made a program that checks a secret key. and another program that supposed to find the secret key. I managed to open a child process in the second program but couldn't send it an input. Here's the program that checks a secret key, secret_key.py:
SECRET_KEY = "hi"
current_key = 0
while not current_key == "exit":
wrong_key = False
current_key = raw_input("Enter the key or enter 'exit' to exit.\n")
for i in range(len(current_key)):
if i < len(SECRET_KEY):
if not current_key[i] == SECRET_KEY[i]:
wrong_key = True
else:
wrong_key = True
if not wrong_key:
print("the key is right!\n")
current_key = "exit"
raw_input("Press ENTER to exit\n")
exit()
Now i made a .sh file to be able to run it in a new terminal as a child process, program.sh:
#! /bin/bash
python Desktop/school/secret_key.py
And here's where i got stuck, find_key.py:
import subprocess
program = subprocess.Popen("./program.sh")
now I could't find a way to send secret_key.py the input it asks for.
Is there anyway I can send a string input to secret_key.py from find_key.py?
To send input to and read output from a process opened via Popen, you can read from and write to the process using the process' stdin and stdout fields. You do need to tell Popen to set up pipes, though:
process = subprocess.Popen([SPIM_BIN] + extra_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
pin = process.stdin
pout = process.stdout
And now you can write to pin and read from pout as you would with any old file descriptor.
Note that this will probably not allow you to connect to the gnome-terminal. But it will allow you to connect to program.sh.

python subprocess: check to see if the executed script is asking for user input

import subprocess
child = subprocess.Popen(['python', 'simple.py'], stdin=subprocess.PIPE)
child.communicate('Alice')
I know you can communicate with executed script via communicate
How do you check for whether a script 'simple.py' is asking for user input?
simple.py could ask for 5-10 user inputs so simply hardcoding communicate wouldnt be enough.
[EDIT]: want to parse the stdout as the script is running and communicate back to the script
while True:
if child.get_stdout() == '?':
# send user input
A simple example:
simple.py:
i = raw_input("what is your name\n")
print(i)
j = raw_input("What is your age\n")
print(j)
Read and write:
import subprocess
child = subprocess.Popen(['python2', 'simple.py'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
for line in iter(child.stdout.readline, ""):
print(line)
if "name" in line:
child.stdin.write("foo\n")
elif "age" in line:
child.stdin.write("100\n")
Output:
what is your name
foo
What is your age
100

How do i output to console while providing input as well?

Essentially, i want what is in this thread: Output to console while preserving user input in ruby, but in Python. I have googled for quite a while, and found an ALMOST working solution, except that it blocked the main thread, as long as i wasn't typing anything in and pressing enter.
Some output of what i don't want to happen is here:
/raw:jtv!jtv#jtv.tmi.twitch.tv PRIVMSG #cobaltstreak :USERCOLOR ullr_son_of_sif #DAA520
Some example input of what i want is:
:jtv!jtv#jtv.tmi.twitch.tv PRIVMSG #cobaltstreak :USERCOLOR ullr_son_of_sif #DAA520
/raw
PRIV:jtv!jtv#jtv.tmi.twitch.tv PRIVMSG #cobaltstreak :SPECIALUSER nightbot subscriber
MSG #cobaltstreak :This shouldn't be here, but on the same line with /raw
This meaning, i want the bottom line of the console to preserve input, while outputting everything happening in the main thread without affecting input.
My current code is:
def console(q, m, lock):
while 1:
raw_input() # After pressing Enter you'll be in "input mode"
with lock:
i = raw_input('> ')
cmd = i.split(' ')[0]
msg = i.strip(cmd + ' ')
q.put(cmd)
m.put(msg)
if cmd == 'quit':
break
as well has:
cmd = cmd_queue.get()
msg = msg_queue.get()
action = cmd_actions.get(cmd)
if action is not None:
action(stdout_lock, msg)
Note the code above is the very first couple of lines in my while loop.
I am on Windows and using python 2.7.6

Running an interactive command from within Python

I have a script that I want to run from within Python (2.6.5) that follows the logic below:
Prompts the user for a password. It looks like ("Enter password: ") (*Note: Input does not echo to screen)
Output irrelevant information
Prompt the user for a response ("Blah Blah filename.txt blah blah (Y/N)?: ")
The last prompt line contains text which I need to parse (filename.txt). The response provided doesn't matter (the program could actually exit here without providing one, as long as I can parse the line).
My requirements are somewhat similar to Wrapping an interactive command line application in a Python script, but the responses there seem a bit confusing, and mine still hangs even when the OP mentions that it doesn't for him.
Through looking around, I've come to the conclusion that subprocess is the best way of doing this, but I'm having a few issues. Here is my Popen line:
p = subprocess.Popen("cmd", shell=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
When I call a read() or readline() on stdout, the prompt is printer to the screen and it hangs.
If I call a write("password\n") for stdin, the prompt is written to the screen and it hangs. The text in write() is not written (I don't the cursor move the a new line).
If I call p.communicate("password\n"), same behavior as write()
I was looking for a few ideas here on the best way to input to stdin and possibly how to parse the last line in the output if your feeling generous, though I could probably figure that out eventually.
If you are communicating with a program that subprocess spawns, you should check out A non-blocking read on a subprocess.PIPE in Python. I had a similar problem with my application and found using queues to be the best way to do ongoing communication with a subprocess.
As for getting values from the user, you can always use the raw_input() builtin to get responses, and for passwords, try using the getpass module to get non-echoing passwords from your user. You can then parse those responses and write them to your subprocess' stdin.
I ended up doing something akin to the following:
import sys
import subprocess
from threading import Thread
try:
from Queue import Queue, Empty
except ImportError:
from queue import Queue, Empty # Python 3.x
def enqueue_output(out, queue):
for line in iter(out.readline, b''):
queue.put(line)
out.close()
def getOutput(outQueue):
outStr = ''
try:
while True: # Adds output from the Queue until it is empty
outStr+=outQueue.get_nowait()
except Empty:
return outStr
p = subprocess.Popen("cmd", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, universal_newlines=True)
outQueue = Queue()
errQueue = Queue()
outThread = Thread(target=enqueue_output, args=(p.stdout, outQueue))
errThread = Thread(target=enqueue_output, args=(p.stderr, errQueue))
outThread.daemon = True
errThread.daemon = True
outThread.start()
errThread.start()
try:
someInput = raw_input("Input: ")
except NameError:
someInput = input("Input: ")
p.stdin.write(someInput)
errors = getOutput(errQueue)
output = getOutput(outQueue)
Once you have the queues made and the threads started, you can loop through getting input from the user, getting errors and output from the process, and processing and displaying them to the user.
Using threading it might be slightly overkill for simple tasks.
Instead os.spawnvpe can be used. It will spawn script shell as a process. You will be able to communicate interactively with the script.
In this example I passed password as an argument, obviously that is not a good idea.
import os
import sys
from getpass import unix_getpass
def cmd(cmd):
cmd = cmd.split()
code = os.spawnvpe(os.P_WAIT, cmd[0], cmd, os.environ)
if code == 127:
sys.stderr.write('{0}: command not found\n'.format(cmd[0]))
return code
password = unix_getpass('Password: ')
cmd_run = './run.sh --password {0}'.format(password)
cmd(cmd_run)
pattern = raw_input('Pattern: ')
lines = []
with open('filename.txt', 'r') as fd:
for line in fd:
if pattern in line:
lines.append(line)
# manipulate lines
If you just want a user to enter a password without it being echoed to the screen just use the standard library's getpass module:
import getpass
print("You entered:", getpass.getpass())
NOTE:The prompt for this function defaults to "Password: " also this will only work on command lines where echoing can be controlled. So if it doesn't work try running it from terminal.

Categories

Resources