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.
CodePudding user response:
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)
CodePudding user response:
I found a way to do so:
It seems like a dirty fix but it's works for me. After someone has su'd, I can add sudo -u <user>
to the front of all their commands so it executes as them while remaining in the script.