On 12/21/14 3:28 PM, Richard W. Marsden wrote: > steps to produce > > hide cursor > setterm -cursor off > > call the bash built-in read command as follows: silent, wait 1 second, read > 1 character to variable KEY > read -s -t 1 -n 1 KEY > > while the read command is in a loop, control + c is trapped successfully > and the cursor is un-hidden > setterm -cursor on > > expected results: > cursor is visible and typed keys are echoed to screen as before > > actual results: > cursor is visible, keys are no-longer echoed to the screen until > terminal is closed > > additional notes > command: setterm -default cannot fix > os: fedora 21 > bash version: bash-4.3.30-2.fc21.x86_64 > tested in various terminal emulators, and the console (alt+Fn, where > n=1-8) > > workaround > remove silent -s from read command
There are a couple of things to note here. First, it's the trap that causes the problem: it short-circuits the normal exit path that would cause the terminal to be cleaned up, then just calls exit instead of killing the shell with SIGINT. (To see why you should do that, read http://www.cons.org/cracauer/sigint.html). If the script died due to SIGINT, the parent bash would notice and restore the terminal settings. Second, you can clean this up without any changes to bash by running a terminal cleanup command (`stty sane', `reset', whatever) in the SIGINT trap. If you would like to take a look at patching bash so you don't have to modify your script, take a look at the attached patch. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRU c...@case.edu http://cnswww.cns.cwru.edu/~chet/
*** ../bash-4.3-patched/shell.c 2014-01-14 08:04:32.000000000 -0500 --- shell.c 2014-12-22 10:27:50.000000000 -0500 *************** *** 74,77 **** --- 74,78 ---- #if defined (READLINE) + # include <readline/readline.h> # include "bashline.h" #endif *************** *** 910,913 **** --- 912,923 ---- fflush (stderr); + /* Clean up the terminal if we are in a state where it's been modified. */ + #if defined (READLINE) + if (RL_ISSTATE (RL_STATE_TERMPREPPED) && rl_deprep_term_function) + (*rl_deprep_term_function) (); + #endif + if (read_tty_modified ()) + read_tty_cleanup (); + /* Do trap[0] if defined. Allow it to override the exit status passed to us. */ *** ../bash-4.3-patched/builtins/read.def 2014-10-01 12:57:38.000000000 -0400 --- builtins/read.def 2014-12-22 10:48:54.000000000 -0500 *************** *** 141,148 **** int sigalrm_seen; ! static int reading; static SigHandler *old_alrm; static unsigned char delim; /* In all cases, SIGALRM just sets a flag that we check periodically. This avoids problems with the semi-tricky stuff we do with the xfree of --- 141,150 ---- int sigalrm_seen; ! static int reading, tty_modified; static SigHandler *old_alrm; static unsigned char delim; + static struct ttsave termsave; + /* In all cases, SIGALRM just sets a flag that we check periodically. This avoids problems with the semi-tricky stuff we do with the xfree of *************** *** 189,193 **** SHELL_VAR *var; TTYSTRUCT ttattrs, ttset; - struct ttsave termsave; #if defined (ARRAY_VARS) WORD_LIST *alist; --- 191,194 ---- *************** *** 222,226 **** USE_VAR(lastsig); ! sigalrm_seen = reading = 0; i = 0; /* Index into the string that we are reading. */ --- 223,227 ---- USE_VAR(lastsig); ! sigalrm_seen = reading = tty_modified = 0; i = 0; /* Index into the string that we are reading. */ *************** *** 439,442 **** --- 440,445 ---- goto assign_vars; } + if (interactive_shell == 0) + initialize_terminating_signals (); old_alrm = set_signal_handler (SIGALRM, sigalrm); add_unwind_protect (reset_alarm, (char *)NULL); *************** *** 483,487 **** --- 486,493 ---- if (i < 0) sh_ttyerror (1); + tty_modified = 1; add_unwind_protect ((Function *)ttyrestore, (char *)&termsave); + if (interactive_shell == 0) + initialize_terminating_signals (); } } *************** *** 498,502 **** --- 504,511 ---- sh_ttyerror (1); + tty_modified = 1; add_unwind_protect ((Function *)ttyrestore, (char *)&termsave); + if (interactive_shell == 0) + initialize_terminating_signals (); } *************** *** 589,592 **** --- 598,603 ---- else lastsig = 0; + if (terminating_signal && tty_modified) + ttyrestore (&termsave); /* fix terminal before exiting */ CHECK_TERMSIG; eof = 1; *************** *** 979,982 **** --- 990,1007 ---- { ttsetattr (ttp->fd, ttp->attrs); + tty_modified = 0; + } + + void + read_tty_cleanup () + { + if (tty_modified) + ttyrestore (&termsave); + } + + int + read_tty_modified () + { + return (tty_modified); } *** ../bash-4.3-patched/builtins/common.h 2014-10-01 12:57:47.000000000 -0400 --- builtins/common.h 2014-12-22 10:10:14.000000000 -0500 *************** *** 123,126 **** --- 141,148 ---- extern void getopts_reset __P((int)); + /* Functions from read.def */ + extern void read_tty_cleanup __P((void)); + extern int read_tty_modified __P((void)); + /* Functions from set.def */ extern int minus_o_option_value __P((char *));