Home > OS >  Python script automatic interaction without 'expect' or 'pexpect'
Python script automatic interaction without 'expect' or 'pexpect'

Time:05-28

I'm trying to write a python script that call a bash script with user interaction. For security reasons, I can't install expect or pexpect on any server -- we have very strict policies.

The bash script is present on multiple servers (called via ssh), so modifing this script is not an option.

My problematic part with the bash script is this:

echo ""
echo "Are you sure you want to continue and $1 the session?"
echo ""
echo -e "Press enter to continue or CTRL-C to abort...\c"
echo -e "Press enter to continue or CTRL-C to abort..."
read line
echo ""
echo "Are you ABSOLUTELY positive?"
echo ""
echo -e "Press enter to continue or CTRL-C to abort...\c"
read line
echo ""

Then from python, for now I tried multiple options either with subprocess.run() and subprocess.Popen()

I went through all these posts: How do I write to a Python subprocess' stdin?

How to make python script press 'enter' when prompted on Shell

Constantly print Subprocess output while process is running

How to make python script press 'enter' when prompted on Shell

None of it seems to work. All my best attempts can print the file of Popen.stdout and then seems to hang at

read line

And even if I do something like:

with subprocess.Popen("confirm.sh", shell = False, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines = False) as con:
    try:
         for line in iter(con.stdout.readline, ""):

            if "enter" in line.decode().strip().split():
                print(line.decode().strip())
                sleep(2)
                con.stdin.write('\n')  # or con.communicate('\n')

I either get this error "I/O operation on closed file." or the script hangs, depending on the method.

It seems that subprocess.run() or subprocess.Popen() look like they want to complete the process and don't allow interaction like pexpect.spawn() would do.

Any ideas resolving this?

CodePudding user response:

Two options come to mind:

  1. use the shell to send the input:
con = subprocess.Popen("{ echo; echo; } | ./confirm.sh", shell = True, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines = False)

The main change being the { echo; echo; } | bits that send two newlines to ./confirm.sh's input stream and the change to shell = True

  1. Use python's communicate method to send two newlines to stdin:
con = subprocess.Popen("./confirm.sh", shell = False, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines = False)
out, err = con.communicate(input='\n\n')

Hat tip to Julia Schwarz's answer for the communicate(input='\n') part.

  • Related