Terminal messed up after exiting bash
Hello, I'd like to report an obscure bug I came across in pfsense which runs on top of FreeBSD. If I run a bash script in which I have read -r -n1 -p "prompt: " and instead of providing input, i ctrl-c the script, the ash shell doesn't recover the terminal properly; backspace echos ^? and the only way to delete characters is to hold shift and press backspace. Also, if I use the -s switch for the read command in the bash script, the problem gets even worse with the cursor not moving anymore as I type and the text I type not being visible at all. A solution was provided by pgas from #bash on irc.freenode.net, where I solve this by trapping the ctrl-c signal and do 'stty cooked' before exiting, which seems to give expected behaviour. Best regards, Jan
Re: read -e does not restore terminal settings correctly when interrupted if a trap is set
On 9/7/14, 6:40 PM, micka...@gmail.com wrote: > Bash Version: 4.3 > Patch Level: 24 > Release Status: release > > Description: > Given the following script (test.sh) : > > #!/bin/bash > cleanup() { :; } > trap cleanup 0 > read -e dummy > > Run the script ('bash test.sh') *in ZSH* and when it waits for an input, > interrupt it with Ctrl-C. Thanks for the report. The problem is that bash doesn't clean up readline and its terminal state in all cases that can result in its calling longjmp() or exiting the shell. I've attached a patch that should fix the problem. The problem doesn't manifest itself in bash because bash saves the terminal state before a command runs and restores it when the command is terminated by a signal. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/ *** ../bash-4.3-patched/bashline.c 2014-05-14 09:22:39.0 -0400 --- bashline.c 2014-09-08 11:28:56.0 -0400 *** *** 203,206 --- 203,207 extern int array_needs_making; extern int posixly_correct, no_symbolic_links; + extern int sigalrm_seen; extern char *current_prompt_string, *ps1_prompt; extern STRING_INT_ALIST word_token_alist[]; *** *** 4209,4214 /* If we're going to longjmp to top_level, make sure we clean up readline. check_signals will call QUIT, which will eventually longjmp to top_level, ! calling run_interrupt_trap along the way. */ ! if (interrupt_state) rl_cleanup_after_signal (); bashline_reset_event_hook (); --- 4262,4268 /* If we're going to longjmp to top_level, make sure we clean up readline. check_signals will call QUIT, which will eventually longjmp to top_level, ! calling run_interrupt_trap along the way. The check for sigalrm_seen is ! to clean up the read builtin's state. */ ! if (terminating_signal || interrupt_state || sigalrm_seen) rl_cleanup_after_signal (); bashline_reset_event_hook (); *** ../bash-4.3-patched/sig.c 2014-01-10 15:06:06.0 -0500 --- sig.c 2014-09-08 11:26:33.0 -0400 *** *** 533,538 /* Set the event hook so readline will call it after the signal handlers finish executing, so if this interrupted character input we can get ! quick response. */ ! if (interactive_shell && interactive && no_line_editing == 0) bashline_set_event_hook (); #endif --- 533,540 /* Set the event hook so readline will call it after the signal handlers finish executing, so if this interrupted character input we can get ! quick response. If readline is active or has modified the terminal we ! need to set this no matter what the signal is, though the check for ! RL_STATE_TERMPREPPED is possibly redundant. */ ! if (RL_ISSTATE (RL_STATE_SIGHANDLER) || RL_ISSTATE (RL_STATE_TERMPREPPED)) bashline_set_event_hook (); #endif
Re: read -e does not restore terminal settings correctly when interrupted if a trap is set
Yep, that fixed the problem, thank you ! 2014-09-08 20:46 GMT+02:00 Chet Ramey : > On 9/7/14, 6:40 PM, micka...@gmail.com wrote: > >> Bash Version: 4.3 >> Patch Level: 24 >> Release Status: release >> >> Description: >> Given the following script (test.sh) : >> >> #!/bin/bash >> cleanup() { :; } >> trap cleanup 0 >> read -e dummy >> >> Run the script ('bash test.sh') *in ZSH* and when it waits for an >> input, >> interrupt it with Ctrl-C. > > Thanks for the report. The problem is that bash doesn't clean up readline > and its terminal state in all cases that can result in its calling > longjmp() or exiting the shell. I've attached a patch that should fix the > problem. > > The problem doesn't manifest itself in bash because bash saves the terminal > state before a command runs and restores it when the command is terminated > by a signal. > > Chet > > > -- > ``The lyf so short, the craft so long to lerne.'' - Chaucer > ``Ars longa, vita brevis'' - Hippocrates > Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: Trap not being run for all CHLD signals, 4.3
On 9/3/14, 10:08 AM, crispusfairba...@gmail.com wrote: > $ cat parallel-test.bash > function process_job { > sleep 1 > } > > function main { > typeset -i index=0 cur_jobs=0 max_jobs=6 > trap '((cur_jobs--))' CHLD > set -m > > while ((index++ < 30)); do > echo -n "index: $index, cur_jobs: $cur_jobs" > set +m > childs=$(pgrep -P $$ | wc -w) > (( childs < cur_jobs )) && echo -n ", actual childs: $childs" > echo > set -m > process_job & > ((++cur_jobs >= max_jobs)) && POSIXLY_CORRECT= wait; > done > > echo 'finished, waiting for remaining jobs...' > wait > } > > main > echo "done" > > This works on: > GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu) > > But on: > GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu) > and > GNU bash, version 4.3.24(1)-release (x86_64-unknown-linux-gnu) > > it will around "index: 9" start missing traps (not decrementing cur_jobs): > > $ bash-4.3.24/bin/bash parallel-test.bash > index: 1, cur_jobs: 0 > index: 2, cur_jobs: 1 > index: 3, cur_jobs: 2 > index: 4, cur_jobs: 3 > index: 5, cur_jobs: 4 > index: 6, cur_jobs: 5 > index: 7, cur_jobs: 5 > index: 8, cur_jobs: 5 > index: 9, cur_jobs: 5, actual childs: 4 > index: 10, cur_jobs: 5, actual childs: 3 > index: 11, cur_jobs: 5, actual childs: 3 > ... > > > If the sleep is changed to be random, it might work correctly for the whole > 30 iterations, which points to a race condition somewhere? The problem is running the wait builtin in posixly-correct mode. That causes the first SIGCHLD to interrupt wait (as Posix requires) and results in timing issues. I will look at making SIGCHLD traps more reliable in the face of the Posix requirements. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: Terminal messed up after exiting bash
This isn't clear to me. Are you using the Almquist Shell to execute BASH to run your script, or is BASH already running when the script is executed? -- Sent from my iPad > On Sep 8, 2014, at 1:17 AM, Jan Rome wrote: > > Hello, > > I'd like to report an obscure bug I came across in pfsense which runs on top > of FreeBSD. > > If I run a bash script in which I have > > read -r -n1 -p "prompt: " > > and instead of providing input, i ctrl-c the script, > > the ash shell doesn't recover the terminal properly; backspace echos ^? and > the only way to delete characters is to hold shift and press backspace. Also, > if I use the -s switch for the read command in the bash script, the problem > gets even worse with the cursor not moving anymore as I type and the text I > type not being visible at all. > > A solution was provided by pgas from #bash on irc.freenode.net, where I solve > this by trapping the ctrl-c signal and do 'stty cooked' before exiting, which > seems to give expected behaviour. > > Best regards, > > Jan >
Re: RFE: remove duplicate entries from the result of `compgen -W'
On Mon, Sep 8, 2014 at 1:07 AM, Chet Ramey wrote: > On 9/4/14, 10:33 PM, Clark Wang wrote: > > See following example: > > > > $ echo $BASH_VERSION > > 4.3.18(1)-release > > $ compgen -W 'hello hello' h > > hello > > hello > > $ > > > > It'll be good if only one "hello" is outputted. > > `complete' and `compgen' only generate lists of possible completions. > Readline performs duplicate removal when it is deciding what to do > with that list. > Thanks, Chet. I did not realized this. In the following example I'll describe my use case and you can understand why my requirement. Many commands like ping and ssh would take a hostname as their parameter. I'm trying to define a common compspec for all these commands since bash-4.1 added the `complete -D' option which is very cool. My idea is just like bash's builtin completion behavior when we input `@' but I'd like the `@' char to be automatically removed when there's only one host matching. See following demo code: function compgen_hosts { local cmd=$1 local cur=$2 local pre=$3 local -a hosts local host hosts=( $(awk '$1 !~ /^ *#/' /etc/hosts) ) if [[ $cur == @* ]]; then host=${cur#*@} COMPREPLY=( $( compgen -P @ -W "${hosts[*]}" "$host") ) fi if [[ ${#COMPREPLY[@]} == 1 ]]; then COMPREPLY[0]=${COMPREPLY[0]#@} fi } complete -D -o nospace -F compgen_hosts For most of the time this works fine. For example: $ foo @host- @host-a.us @host-b.us $ foo @host-a $ foo host-a.us But there's a small problem because there are duplicate hostnames. For example both `127.0.0.1` and `::1` are mapping to `localhost' and then my code would not work: $ foo @localhost @localhost $ The reason is the `if [[ ${#COMPREPLY[@]} == 1 ]]' condition. For `localhost' there are two candidates in COMPREPLY: COMPREPLY=( localhost localhost ) I know I can manually remove duplicate entries (either when reading /etc/hosts or from the output of compgen) but it would be convenient if the result of compgen has already done that for me. :) Thanks. -clark > > Chet > > -- > ``The lyf so short, the craft so long to lerne.'' - Chaucer > ``Ars longa, vita brevis'' - Hippocrates > Chet Ramey, ITS, CWRUc...@case.edu > http://cnswww.cns.cwru.edu/~chet/ >