How i can interact with some CLI runned in terminal? - python

For now i have some Command-Line Interface which one i need to interact. (e.g. run this CLI in terminal, then execute few comands inside of it).
In terminal it looks the next way:
blabla-cli
some-comand
%response%
next-command
And all of it i want to automate with python.
Almost all what i could fing in the Google is about using Popen and comunicate or process.stdin to do what i want.
But in case of using provided code i can't send any comand to process, i mean "help" wont be sended to terminal
args = ["blabla-cli"]
process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8')
process.wait()
process.stdin.writelines('help')
process.wait()
print(process.stdout.readlines())
I expect to send some command to terminal via python code, get some response and get some actions with recieved response.

Related

python sending argument to a running process

I have a flutter project called zed, my goal is to monitor the output of flutter run, as long as pressing r, the output will increase.
To automatically implement this workflow, my implementation is
import subprocess
bash_commands = f'''
cd ../zed
flutter run --device-id web-server --web-hostname 192.168.191.6 --web-port 8352
'''
process = subprocess.Popen('/bin/bash', stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=False)
output, err= process.communicate(bash_commands.encode('utf-8'))
print(output, err)
output, _ = process.communicate('r'.encode('utf-8'))
print(output)
It's not working as I expected, there is nothing printed on the screen.
Use process.stdin.write() instead of process.communicate()
process.stdin.write(bash_commands)
process.stdin.flush()
But why you ask
Popen.communicate(input=None, timeout=None)
Interact with process:
Send data to stdin. Read data from stdout and stderr, until
end-of-file is reached
https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate
communicate(...) doesn't return until the pipe is closed which typically happens when the subprocess closes. Great for ls -l not so good for long running subprocesses.

How to capture stdout of shell after switching users

I'm making a shell with python. So far I have gotten cd to work (not pretty I know, but it's all I need for now). When I su root (for example) I get a root shell, but I can't capture the output I receive after running a command. However the shell does accept my commands, as when I type exit it exits. Is there a way to capture the output of a 'new' shell?
import os, subprocess
while True:
command = input("$ ")
if len(command.split(" ")) >= 2:
print(command.split(" ")[0]) #This line is for debugging
if command.split(" ")[0] == "cd" or command.split(" ")[1] == "cd":
os.chdir(command.split(" ")[command.split(" ").index("cd") + 1])
continue
process = subprocess.Popen(command.split(), stdout=subprocess.PIPE, universal_newlines=True)
output, error = process.communicate()
print(output.strip("\n"))
EDIT: To make my request a bit more precise, I'd like a way to authenticate as another user from a python script, basically catching the authentication, doing it in the background and then starting a new subprocess.
You really need to understand how subprocess.Popen works. This command executes a new sub-process (on a Unix machine, calls fork and then exec). The new sub-process is a separate process. Your code just calls communicate once and then discards of it.
If you just create a new shell by calling subprocess.Popen and then running su <user> inside of it, the shell will be closed right after that and the next time, you'll be running the command using the same (original) user again.
What you want is probably to create a single subprocess at the beginning of your application and then be a sort of a proxy between the user and the underlying process, and then just keep writing to its stdin and reading from stdout.
Here's an example:
import os, subprocess
process = subprocess.Popen(["bash"], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, universal_newlines=True)
while True:
command = input("$ ")
process.stdin.write(command + "\n")
process.stdin.flush()
output = process.stdout.readline()
print(output.strip("\n"))
(I removed the cd command parsing bit because it wasn't constructive to understanding the solution here, but you can definitely add specific handlers for specific inputs that wrap the underlying shell)

Run a program in the background and then open another program using subprocess

On the terminal, I have two programs to run using subprocess
First, I will call ./matrix-odas & so the first program will run in the background and I can then type the second command. The first command will return some messages.
The second command ~/odas/bin/odaslive -vc ~/odas/config/odaslive/matrix_creator.cfg will open the second program and it will keep running and keep printing out text. I'd like to use subprocess to open these programs and capture both outputs.
I have never used subprocess before and following tutorials, I am writing the script on Jupyter notebook (python 3.7) in order to see the output easily.
from subprocess import Popen, PIPE
p = Popen(["./matrix-odas", "&"], stdout=PIPE, stderr=PIPE, cwd=wd, universal_newlines=True)
stdout, stderr = p.communicate()
print(stdout)
This is the code that i tried to open the first program. But Jupyter notebook always gets stuck at p.communicate() and I can't see the messages. Without running the first program in the background, I won't be able to get the command prompt after the messages are printed.
I would like to know what subprocess function should I use to solve this issue and which platform is better to test subprocess code. Any suggestions will be appreciated. Thank you so much!
From this example at the end of this section of the docs
with Popen(["ifconfig"], stdout=PIPE) as proc:
log.write(proc.stdout.read())
it looks like you can access stdout (and I would assume stderr) from the object directly. I am not sure whether you need to use Popen as a context manager to access that property or not.

Retrieving files from CVS repository by executing windows commands line from a python script based upon the input specified by the user

I have few command line interface command which are executable using windows command prompt.There are few commands that I have used to retrieve files from CVS repository using command prompt.Now I want to execute these commands by means of a python script.I have found out that I have to use subprocess inorder to interact with command prompt by means of a python script.I am trying to run the piece of code below to retrieve files from CVS repository by means of HEAD.When I try to execute these commands directly from command prompt they execute properly.I can see that it creates a local workspace and it retrieves files properly.But when i execute python script,it doesn't perform any action.I need your help.I also want to retrieve files by means of tag.
import os
import sys
import subprocess
Current_Working_Directory=os.getcwd()
print "Current_Working_Directory",Current_Working_Directory
cmd = ['cvs',
'-d:::pserver:<username>#<computername>:<repository>
'login']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
output=p.communicate()
print "p",p
cmd1=['set','CVSROOT','=','pserver:<username>#<computername>:<repository>']
p1 = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
print p1
cmd2=['cvs','co','-r','HEAD','Test']
p2 = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
print p2
Running subprocess.Popen creates a new subprocess. The CVSROOT envioronment variable will only exist for the brief existence of that subprocess so it will not be around for the next Popen which executes the cvs command. You want to do os.environ["CVSROOT"] = 'pserver:<username>#<computername>:<repository>' instead.
In fact, if you do that before the cvs login you shouldn't need to specify it explicitly in that command either.
The alternative is to specify the cvsroot with -d in the cvs co command as you did with the cvs login command.

Application is not prompting confirmation message during runtime via popen in python

I have a application which I have to load via POpen in python.During runtime,application will prompt a confirmation message stating "Can I continue?".Over here,we have to provide yes/no option.
The POpen executes the command properly but the application doesn't prompt for "Can I continue" message.It just stops at that point.If I run the application manually,application prompts for confirmation message.
proc=subprocess.Popen(['app.exe -start'],shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
Let me know in case I am missing some parameters.
If you pass the stdout=subprocess.PIPE option, the output is redirected to a PIPE and not displayed. You can compare those two functions :
p1 = subprocess.Popen(["ls"])
p2 = subprocess.Popen(["ls"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
The first one prints the output of the command, the second does not. But you can access it with p2.stdout.read().
So if you want to see the output of your script (and to manually type the confirmation), use
proc = subprocess.Popen(['app.exe -start'], shell=True)
Else, you have to interact with proc.stdin and proc.stdout
PS : The use of shell=True is discouraged, remove it if you can. It is especially important if the command you want to run contains some user input.

Categories