Last active
October 9, 2016 16:09
-
-
Save garybernhardt/d496c69bf9e7cc03ddbd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is a stripped-down example based on Selecta's TTY handling. We store the | |
# TTY state in `tty_state`, then go into an infinite loop. When the loop is | |
# terminated by a ^C, we try to restore the TTY state. It's important that this | |
# work, but it doesn't in some subtle situations, and I don't know why. | |
# | |
# Save this file as test.rb and run it via this command, where `stty` should | |
# successfully restore the TTY state: | |
# bash -c 'echo | ruby test.rb' | |
# | |
# Next, run it via this command, where `stty` should fail to restore the TTY | |
# state: | |
# bash -c 'echo $(echo | ruby test.rb)' | |
# | |
# Clearly, the command substitution matters, but I don't know why. Initially, I | |
# thought that the TTY file might be gone by the time the SIGINT is sent, | |
# meaning there would be nothing for `stty` to see. However, you can see that | |
# in both commands the TTY file is still there. | |
# | |
# Here's what I get when I run those two commands and ^C them (on OS X 10.10, | |
# but this problem was originally observed in Linux): | |
# | |
# $ bash -c 'echo | ruby test.rb' | |
# ^C | |
# Did stty succeed?: true | |
# Is /dev/tty still there?: true | |
# | |
# $ bash -c 'echo $(echo | ruby test.rb)' | |
# ^C | |
# stty: tcsetattr: Input/output error | |
# | |
# Did stty succeed?: false | |
# Is /dev/tty still there?: true | |
tty_state = `stty -f /dev/tty -g` | |
begin | |
loop do end | |
rescue Interrupt | |
# Swallow the exception | |
ensure | |
$stderr.puts `stty -f /dev/tty #{tty_state}` | |
$stderr.puts "Did stty succeed?: #{$?.success?}" | |
$stderr.puts "Is /dev/tty still there?: #{!open("/dev/tty", "w").closed?}" | |
end |
What do I get for breaking the "it should work" case?
$ bash -c 'echo | ruby test.rb'
stty: when specifying an output style, modes may not be set
^Cstty: standard input: Invalid argument
Did stty succeed?: false
Is /dev/tty still there?: true
$ bash -c 'echo $(echo | ruby test.rb)'
stty: when specifying an output style, modes may not be set
^C
stty: standard input: Invalid argument
Did stty succeed?: false
Is /dev/tty still there?: true
starting bash 4.1.5(1)-release via zsh 4.3.10 in tmux 1.3-2+squeeze1 on Debian Squeeze, connected via putty 0.64
I don't have any solution or explanation, but I took your question as a chance to learn a bit about TTYs. In my fiddling, I found that this actually works with dash
as opposed to bash
and thought you might appreciate knowing, given that they handle SIGNIT
differently (cf. this). Good luck!
ttystate doesn't possibly have some character in it that are only metacharacters in bash, but not in dash, does it?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For anyone tinkering with this: with "stty (GNU coreutils) 8.23" I had to change the
-f
to-F
in the two stty commands to reproduce.