I'm writing a bash script to read some user input (like a password request), and I'd like to capture the result and pass it through its stdout. (I'm working in a GNU/Linux environment, with recent software).

Here is a simplified version of the script that reproduces the issues


# read_input.sh
# Issue B : redirection of "3>&1" here causes stty error when                                             
# this script is executed via a command subsitution context subshell                                                                       
exec 3>&1 </dev/tty >/dev/tty                                                                                     

tty_settings=`stty -g`                                                                                            

# Issue A : uncommented version doesn't restore tty properly.                                                     
#trap 'stty "$tty_settings";' EXIT                                                                                
#trap 'echo "...interrupting"; exit 1' INT ABRT HUP QUIT TERM                                                     
trap 'echo "...interrupting"; stty "$tty_settings"; exit 1' INT ABRT HUP QUIT TERM                                

stty -echo                                                                                                        

echo "Enter input: "                                                                                              
while IFS= read -r -n1 char; do                                                                                   
    # nb: stripped out proper char handling code here,                                                            
    # (except return), for simplicity                                                                             
    if [[ $char = "" ]]; then                                                                                     
    echo -n "*"
echo ""

stty "$tty_settings"


echo "$input" >&3

The intention is to write to fd 3 the result input (if this script's stdout on invocation is connected in a pipe) - while still having tty during interaction. I then modify the tty with stty to control echo, etc, restoring any modifications via handling with trap.

I've encountered two problems with this.

Issue A

On restoration to the controlling terminal, echo was suppressed. I had to use the two line trap handling case (commented out), instead of the active one line handler case uncommented.

In the one line case - say on INT : the tty is restored, then exit is called via the handler. I'm not trapping EXIT itself - why would that be required?

Issue B

This is related to exec's "3>&1" redirection in a subshell context.

For some reason, say I run this script ("read_input.sh") in a subshell - and want to grab its output from another script via command substitution:


# read_input_caller.sh
input=$(sh read_input.sh)
echo "$input"

I found the stty invocation in the trap handler complained with the following on interrupting the calling script (say with ^C):

stty: 'standard input': Input/output error

That error message only happens because of the "3>&1" redirection in the exec line - calling that exec line without "3>&1", there's no stty error (but not very useful for passing the input to stdout). I can't think why this would be the case?

In the calling script, another subshell invocation like


sh read_input.sh | cat

Does not produce this error.

Interestingly, when issue B ocurred, the controlling terminal's tty seemed to be restored properly, even under the problematic trapping/restoration of issue A.

  • You could sidestep all this in bash with read -s -p "Password: " password – roaima Sep 9 '17 at 19:16
  • Do you have a literal ... in your trap statements? – Mark Plotnick Sep 10 '17 at 2:20
  • @MarkPlotnick, the "..." was just to say I was trapping some other signals in that line, too (eg TERM, HUP, etc.,), it is not literally what is written in the script. – Stephen Brown Sep 10 '17 at 10:38
  • @roaima : I wanted a fancier input which echoed as I typed (eg with *s). For issue B, the whole subshell thing is not necessary - I could wrap the input reading routine as a function and source the function directly in the caller (but curiosity remains as to why command subsitution causes the issue.) – Stephen Brown Sep 10 '17 at 11:26
  • It would help us if you could show a more complete (no ellipses), but minimal, example of the script that illustrates the problem. – Mark Plotnick Sep 10 '17 at 11:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.