Running bash in subprocess breaks stdout of tty if interrupted while waiting on `read -s`?
Question: As @Bakuriu points out in the comments this is basically the same problem as
in [BASH: Ctrl+C during input breaks current
terminal](http://stackoverflow.com/questions/31808863/bash-ctrlc-during-input-
breaks-current-terminal) However, I can only reproduce the problem when bash
is run as a subprocess of another executable, and not directly from bash,
where it seems to handle terminal cleanup fine. I would be interested in an
answer as to why bash seems to be broken in this regard.

I have a Python script meant to log the output of subprocess that is started
by that script. If the subprocess happens to be a bash script that at some
point reads user input by calling the `read -s` built-in (the `-s`, which
prevents echoing of entered characters, being key), and the user interrupts
the script (i.e. by Ctrl-C), then bash fails to restore output to the tty,
even though it continues to accept input.

I whittled this down to a simple example:

    
    
    $ cat test.py
    #!/usr/bin/python
    import subprocess as sp
    p = sp.Popen(['bash', '-c', 'read -s foo; echo $foo'])
    p.wait()
    

Upon running `./test.py` it will wait for some input. If you type some input
and press Enter the script returns and echos your input as expected, and there
is no issue. However, if you immediately hit "Ctrl-C", Python displayed a
traceback for the `KeyboardInterrupt`, and then returns to the bash prompt.
However, nothing you type is displayed to the terminal. Typing `reset<enter>`
successfully resets the terminal, however.

I'm somewhat at a loss as to exactly what's happening here.

**Update:** I managed to reproduce this without Python in the mix either. I
was trying to run bash in strace to see if I could glean anything that was
going on. With the following bash script:

    
    
    $ cat read.sh
    #!/bin/bash
    read -s foo
    echo $foo
    

Running `strace ./read.sh` and immediately hitting Ctrl-C produces:

    
    
    ...
    ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon -echo ...}) = 0
    brk(0x1a93000)                          = 0x1a93000
    read(0, Process 25487 detached
     <detached ...>
    

Where PID 25487 was `read.sh`. This leaves the terminal in the same broken
state. However, `strace -I1 ./read.sh` simply interrupts the `./read.sh`
process and returns to a normal, non-broken terminal.


Answer: It seems like this is related to the fact that `bash -c` starts a **non-
interactive** shell. This probably prevents it from restoring the terminal
state.

To explicitly start an interactive shell you can just pass the `-i` option to
bash.

    
    
    $ cat test_read.py 
    #!/usr/bin/python3
    from subprocess import Popen
    p = Popen(['bash', '-c', 'read -s foo; echo $foo'])
    p.wait()
    $ diff test_read.py test_read_i.py 
    3c3
    < p = Popen(['bash', '-c', 'read -s foo; echo $foo'])
    ---
    > p = Popen(['bash', '-ic', 'read -s foo; echo $foo'])
    

When I run and press `Ctrl`+`C`:

    
    
    $ ./test_read.py
    

I obtain:

    
    
    Traceback (most recent call last):
      File "./test_read.py", line 4, in <module>
        p.wait()
      File "/usr/lib/python3.5/subprocess.py", line 1648, in wait
        (pid, sts) = self._try_wait(0)
      File "/usr/lib/python3.5/subprocess.py", line 1598, in _try_wait
        (pid, sts) = os.waitpid(self.pid, wait_flags)
    KeyboardInterrupt
    

and the terminal isn't properly restored.

If I run the `test_read_i.py` file in the same way I just get:

    
    
    $ ./test_read_i.py 
    
    $ echo hi
    hi
    

no error, and terminal works.

