GIT hook -> Python -> Bash: How to read user input?

Question:

I’m doing a GIT hook in Python 3.5. The python script calls a Bash script that that reads input from the user using read command.

The bash script by itself works, also when calling directly the python script, but when GIT runs the hook written in Python, it doesn’t work as expected because no user input is requested from the user.

Bash script:

#!/usr/bin/env bash

echo -n "Question? [Y/n]: "
read REPLY

GIT Hook (Python script):

#!/usr/bin/env python3    
from subprocess import Popen, PIPE
proc = Popen('/path/to/myscript.sh', shell=True, stderr=PIPE, stdout=PIPE)        
stdout_raw, stderr_raw= proc.communicate()

When I execute the Python script, Bash’s read does not seem to be waiting for an input, and I only get:

b'nQuestion? [Y/n]: n'

How to let the bash script read input when being called from Python?

Asked By: arod

||

Answers:

Adding

print(stdout_raw)
print(stderr_raw)

Shows

b''
b'/bin/sh: myscript.sh: command not foundn'

here. Adding ./ to the myscript.sh worked for the READ once python could find the script. cwd=’.’ in Popen may also work.

Answered By: Brian Tiffin

It turns out the problem had nothing to do with Python: if the GIT hook called a bash script it also failed to ask for input.

The solution I found is given here.

Basically, the solution is to add the following to the bash script before the read:

# Allows us to read user input below, assigns stdin to keyboard
exec < /dev/tty

In my case, I also had to call the bash process simply like Popen(mybashscript) instead of Popen(mybashscript, shell=True, stderr=PIPE, stdout=PIPE)), so the script can freely output to STDOUT and not get captured in a PIPE.

Alternatively, I didn’t modify the bash script and instead used in Python:

sys.stdin = open("/dev/tty", "r")
proc = Popen(h, stdin=sys.stdin)

which is also suggested in the comments of the aforementioned link.

Answered By: arod

This is what worked for me without invoking a bash script from within python. It is a modified version from arod’s answer.

    import subprocess
    import sys

    sys.stdin = open("/dev/tty", "r")
    user_input = subprocess.check_output("read -p "Please give your input: " userinput && echo "$userinput"", shell=True, stdin=sys.stdin).rstrip()

    print(user_input)
Answered By: Tano

Based on the above replies:

import sys
import subprocess

def getInput(prompt):
    sys.stdin = open("/dev/tty", "r")
    command = f"read -p "{prompt}" ret && echo "$ret""
    userInput = subprocess.check_output(command, shell=True, stdin=sys.stdin).rstrip().decode("utf-8")
    return userInput
Answered By: nvd
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.