Bash: pressing tab to select entry in reverse-i-search freezes the terminal #19233

Closed
opened 2026-01-31 06:37:36 +00:00 by claunia · 18 comments
Owner

Originally created by @derekthesnake on GitHub (Jan 18, 2023).

Windows Terminal version

1.15.3465.0

Windows build number

Version 10.0.19044.2364

Other Software

GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)

Steps to reproduce

Control + Shift + R to enter reverse-i-search, type to bring up a command then press TAB to try to select it.

Expected Behavior

The command should be put at the prompt and the terminal should remain interactive.

Actual Behavior

The command does get placed at the prompt but the terminal becomes unresponsive. Control-C is the only input that registers to the screen, but it doesn't unfreeze the terminal. All other keypresses seem to have no effect, although the blinking cursor does pause blinking when other keys are pressed so it seems that they are registered to some degree.

Originally created by @derekthesnake on GitHub (Jan 18, 2023). ### Windows Terminal version 1.15.3465.0 ### Windows build number Version 10.0.19044.2364 ### Other Software GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu) ### Steps to reproduce Control + Shift + R to enter reverse-i-search, type to bring up a command then press TAB to try to select it. ### Expected Behavior The command should be put at the prompt and the terminal should remain interactive. ### Actual Behavior The command does get placed at the prompt but the terminal becomes unresponsive. Control-C is the only input that registers to the screen, but it doesn't unfreeze the terminal. All other keypresses seem to have no effect, although the blinking cursor does pause blinking when other keys are pressed so it seems that they are registered to some degree.
claunia added the Needs-TriageIssue-BugNeeds-Attention labels 2026-01-31 06:37:36 +00:00
Author
Owner

@DHowett commented on GitHub (Jan 18, 2023):

Are you using bash inside WSL, or via SSH or something?

I don't believe that Tab is the canonical way to select a result from bck-i-search, so I believe that you're triggering tab completion instead of accepting the result.

In WSL, tab completion definitely takes a while because WSL adds all of \windows\system32 (and the rest of your Windows PATH) to PATH.

FWIW: I can reproduce similar behavior on Linux directly with a PATH that contains slow storage.

@DHowett commented on GitHub (Jan 18, 2023): Are you using bash inside WSL, or via SSH or something? I don't believe that <kbd>Tab</kbd> is the canonical way to select a result from `bck-i-search`, so I _believe_ that you're triggering tab completion instead of accepting the result. In WSL, tab completion definitely takes a while because WSL adds all of `\windows\system32` (and the rest of your Windows `PATH`) to `PATH`. FWIW: I can reproduce similar behavior on Linux directly with a `PATH` that contains slow storage.
Author
Owner

@derekthesnake commented on GitHub (Jan 18, 2023):

Oh, yep, sorry forgot to include WSL.

Hmm... I'll do some more investigating about the tab completion. Interesting behavior then, on my Linux hardware it wasn't triggering tab completion, just selecting the command. I'll look into the versions of bash I suppose.

@derekthesnake commented on GitHub (Jan 18, 2023): Oh, yep, sorry forgot to include WSL. Hmm... I'll do some more investigating about the tab completion. Interesting behavior then, on my Linux hardware it wasn't triggering tab completion, just selecting the command. I'll look into the versions of bash I suppose.
Author
Owner

@DHowett commented on GitHub (Jan 18, 2023):

qq: If you were to export PATH=/bin:/sbin:/usr/bin:/usr/sbin before you do a bck-i-search + Tab, does it get better?

@DHowett commented on GitHub (Jan 18, 2023): qq: If you were to `export PATH=/bin:/sbin:/usr/bin:/usr/sbin` before you do a `bck-i-search` + <kbd>Tab</kbd>, does it get better?
Author
Owner

@ghost commented on GitHub (Jan 22, 2023):

This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment.

@ghost commented on GitHub (Jan 22, 2023): This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**.
Author
Owner

@JL102 commented on GitHub (Sep 30, 2023):

Hi @DHowett I'm experiencing the same problem. Do you have the ability to reopen this issue?

I ran export PATH=/bin:/sbin:/usr/bin:/usr/sbin before doing reverse-i-search and yes, it gets better.
I don't think it's entirely the fault of system32. I copied my entire PATH and removed /mnt/c/Windows/System32 from it, and I still got a long delay (I have a loooot of folders on my system PATH on Windows, so there's still a lot of items there).

I don't understand, though - Why would having a lot of items on your PATH affect reverse-i-search? Like, normal tab completion doesn't have the same delay. If I type explo and press tab, it autocompletes to explorer within about 1 second and then if I type out explorer.e and press tab again, it autocompletes to explorer.exe again within about 1 second. And actually running reverse-i-search seems to have no delay at all, i.e. when I type it searches through my bash history really quickly. So what's it doing in the background after I press tab to fill out the whole command?

Thanks!

@JL102 commented on GitHub (Sep 30, 2023): Hi @DHowett I'm experiencing the same problem. Do you have the ability to reopen this issue? I ran `export PATH=/bin:/sbin:/usr/bin:/usr/sbin` before doing reverse-i-search and yes, it gets better. I don't think it's entirely the fault of system32. I copied my entire PATH and removed `/mnt/c/Windows/System32` from it, and I still got a long delay (I have a loooot of folders on my system PATH on Windows, so there's still a lot of items there). I don't understand, though - Why would having a lot of items on your PATH affect `reverse-i-search`? Like, normal tab completion doesn't have the same delay. If I type `explo` and press tab, it autocompletes to `explorer` within about 1 second and then if I type out `explorer.e` and press tab again, it autocompletes to `explorer.exe` again within about 1 second. And actually _running_ `reverse-i-search` seems to have no delay at all, i.e. when I type it searches through my bash history really quickly. So what's it doing in the background after I press tab to fill out the whole command? Thanks!
Author
Owner

@JL102 commented on GitHub (Sep 30, 2023):

I don't believe that Tab is the canonical way to select a result from bck-i-search, so I believe that you're triggering tab completion instead of accepting the result.

What is the normal way to select a result from reverse-i-search?

EDIT: I think you're on to something, but I think it's a little more complicated than just triggering tab completion.

The "recent command" I'm using to test this behavior is this:

time make run-binary-debug BINARY=~/chipyard/tests/hello.riscv

If, instead of pressing tab after reverse-i-search, I paste it into the terminal and then press tab in the end, nothing special happens. If I remove a few characters from the end and then press tab, then it completes instantaneously. HOWEVER, if I move my cursor to the very start of the line and then press tab, I get the same excruciatingly long delay before the terminal starts responding again.

If I have top running in the background, I can see bash is taking a chunk of my CPU while it's figuring things out:

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND 
22247 drak      20   0   13664   8860   3528 D  13.7   0.0   0:31.39 bash

Any idea why there's only a significant delay when I press tab while the cursor is at the start of the line?

@JL102 commented on GitHub (Sep 30, 2023): > I don't believe that Tab is the canonical way to select a result from bck-i-search, so I believe that you're triggering tab completion instead of accepting the result. What **is** the normal way to select a result from `reverse-i-search`? EDIT: I think you're on to something, but I think it's a little more complicated than just triggering tab completion. The "recent command" I'm using to test this behavior is this: ``` time make run-binary-debug BINARY=~/chipyard/tests/hello.riscv ``` If, instead of pressing tab after `reverse-i-search`, I paste it into the terminal and then press tab in the end, nothing special happens. If I remove a few characters from the end and then press tab, then it completes instantaneously. HOWEVER, if I move my cursor to the very start of the line and then press tab, I get the same excruciatingly long delay before the terminal starts responding again. If I have `top` running in the background, I can see `bash` is taking a chunk of my CPU while it's figuring things out: ``` PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 22247 drak 20 0 13664 8860 3528 D 13.7 0.0 0:31.39 bash ``` Any idea why there's **only** a significant delay when I press tab while the cursor is at the start of the line?
Author
Owner

@DHowett commented on GitHub (Oct 5, 2023):

Hey @JL102! Sorry to leave you on read for a couple days.

So, what I believe is happening is that bash is scanning every directory in $PATH for commands whose names match the input up to the cursor. When there's nothing, everything matches. When there's something, very few things match. Now that's not usually a problem of course... but WSL is an interesting beast.

/mnt/c is a 9p network share that talks to a userland process on the Windows side. That's not really that slow either, but it's definitely much slower than direct VHD access (like /.) I think enumerating a directory over 9p is pretty slow... but it also gets a bit worse when (again, I think!) bash has to stat() every file to determine whether it's executable (!). stat on Windows is terrifically slow.

(I don't know if stat info comes back with readdir... but if it does, then it's just the Windows P9 server doing the slow statting rather than bash 😄)

What is the normal way to select a result from reverse-i-search?

You know, I never thought about this! I always use the right arrow, which breaks out of bck-i-search and moves the cursor simultaneously. 🤷

@DHowett commented on GitHub (Oct 5, 2023): Hey @JL102! Sorry to leave you on read for a couple days. So, what I _believe_ is happening is that bash is scanning every directory in `$PATH` for commands whose names match the input up to the cursor. When there's nothing, everything matches. When there's something, very few things match. Now that's not usually a problem of course... but WSL is an interesting beast. `/mnt/c` is a 9p network share that talks to a userland process on the Windows side. That's not really that slow either, but it's definitely much slower than direct VHD access (like `/`.) I think enumerating a directory over 9p is pretty slow... but it also gets a bit worse when (again, I think!) bash has to `stat()` _every file_ to determine whether it's executable (!). `stat` on Windows is terrifically slow. (I don't know if `stat` info comes back with `readdir`... but if it does, then it's just the Windows P9 server doing the slow statting rather than bash :smile:) > What **is** the normal way to select a result from `reverse-i-search`? You know, I never thought about this! I always use the right arrow, which breaks out of bck-i-search and moves the cursor simultaneously. :shrug:
Author
Owner

@JL102 commented on GitHub (Oct 6, 2023):

@DHowett Thanks for the explanation! Really sucks that it does this, but your answer seems to make sense.

So, what I believe is happening is that bash is scanning every directory in $PATH for commands whose names match the input up to the cursor. When there's nothing, everything matches. When there's something, very few things match. Now that's not usually a problem of course... but WSL is an interesting beast.

Hmm. The explanation makes sense for what's causing it to take so long, but I still don't get why Bash is (probably) triggering tab autocompletion when I exit reverse-i-search. When exiting reverse-i-search, the command is fully populated, so I don't see any need for the tab autocompletion to run. Do you think it may be a bug in Bash, or is there a potential reason for it to behave this way?

@JL102 commented on GitHub (Oct 6, 2023): @DHowett Thanks for the explanation! Really sucks that it does this, but your answer seems to make sense. > So, what I believe is happening is that bash is scanning every directory in $PATH for commands whose names match the input up to the cursor. When there's nothing, everything matches. When there's something, very few things match. Now that's not usually a problem of course... but WSL is an interesting beast. Hmm. The explanation makes sense for what's causing it to take so long, but I still don't get why Bash is (probably) triggering tab autocompletion when I exit `reverse-i-search`. When exiting `reverse-i-search`, the command is fully populated, so I don't see any need for the tab autocompletion to run. Do you think it may be a bug in Bash, or is there a potential reason for it to behave this way?
Author
Owner

@JosefSaltz commented on GitHub (Mar 1, 2024):

I am still having this issue as of end of February 2024. The right arrow method works but it's a pain that this can't handle the autocomplete.

@JosefSaltz commented on GitHub (Mar 1, 2024): I am still having this issue as of end of February 2024. The right arrow method works but it's a pain that this can't handle the autocomplete.
Author
Owner

@mrankine commented on GitHub (Mar 15, 2024):

Likewise. Hitting tab to select a reverse-i-search feels the natural thing to do, but the terminal freezes and can't be fixed even with a Ctrl-C.

@mrankine commented on GitHub (Mar 15, 2024): Likewise. Hitting tab to select a `reverse-i-search` feels the natural thing to do, but the terminal freezes and can't be fixed even with a `Ctrl-C`.
Author
Owner

@JL102 commented on GitHub (Mar 15, 2024):

FYI, I've been working around this by pressing End on my keyboard instead of tab.

@JL102 commented on GitHub (Mar 15, 2024): FYI, I've been working around this by pressing `End` on my keyboard instead of tab.
Author
Owner

@JohnRDOrazio commented on GitHub (Oct 17, 2024):

I've been having the same problem in a WSL terminal, and just stumbled upon this issue which explains what is happening. I spontaneously used Tab to select the current result, I guess I should use the right arrow or End from now on.

@JohnRDOrazio commented on GitHub (Oct 17, 2024): I've been having the same problem in a WSL terminal, and just stumbled upon this issue which explains what is happening. I spontaneously used <kbd>Tab</kbd> to select the current result, I guess I should use the <kbd>→</kbd> right arrow or <kbd>End</kbd> from now on.
Author
Owner

@dwymark-celestron commented on GitHub (Mar 7, 2025):

This issue is still reproducing on Ubuntu WSL in Windows 11. The ticket ought to be reopened.

@dwymark-celestron commented on GitHub (Mar 7, 2025): This issue is still reproducing on Ubuntu WSL in Windows 11. The ticket ought to be reopened.
Author
Owner

@DHowett commented on GitHub (Mar 7, 2025):

This issue is still reproducing on Ubuntu WSL in Windows 11. The ticket ought to be reopened.

@dwymark-celestron is the explanation above (copied here below) unsuitable?

So, what I believe is happening is that bash is scanning every directory in $PATH for commands whose names match the input up to the cursor. When there's nothing, everything matches. When there's something, very few things match. Now that's not usually a problem of course... but WSL is an interesting beast.

/mnt/c is a 9p network share that talks to a userland process on the Windows side. That's not really that slow either, but it's definitely much slower than direct VHD access (like /.) I think enumerating a directory over 9p is pretty slow... but it also gets a bit worse when (again, I think!) bash has to stat() every file to determine whether it's executable (!). stat on Windows is terrifically slow.

(I don't know if stat info comes back with readdir... but if it does, then it's just the Windows P9 server doing the slow statting rather than bash 😄)

What is the normal way to select a result from reverse-i-search?

You know, I never thought about this! I always use the right arrow, which breaks out of bck-i-search and moves the cursor simultaneously. 🤷

The TL;DR is: Windows Terminal and the Windows Console Subsystem are not responsible for this behavior. Your shell is.

@DHowett commented on GitHub (Mar 7, 2025): > This issue is still reproducing on Ubuntu WSL in Windows 11. The ticket ought to be reopened. @dwymark-celestron is the explanation above (copied here below) unsuitable? > So, what I _believe_ is happening is that bash is scanning every directory in `$PATH` for commands whose names match the input up to the cursor. When there's nothing, everything matches. When there's something, very few things match. Now that's not usually a problem of course... but WSL is an interesting beast. > > `/mnt/c` is a 9p network share that talks to a userland process on the Windows side. That's not really that slow either, but it's definitely much slower than direct VHD access (like `/`.) I think enumerating a directory over 9p is pretty slow... but it also gets a bit worse when (again, I think!) bash has to `stat()` _every file_ to determine whether it's executable (!). `stat` on Windows is terrifically slow. > > (I don't know if `stat` info comes back with `readdir`... but if it does, then it's just the Windows P9 server doing the slow statting rather than bash 😄) > > > What **is** the normal way to select a result from `reverse-i-search`? > > You know, I never thought about this! I always use the right arrow, which breaks out of bck-i-search and moves the cursor simultaneously. 🤷 The TL;DR is: Windows Terminal and the Windows Console Subsystem are not responsible for this behavior. Your shell is.
Author
Owner

@JohnRDOrazio commented on GitHub (Mar 7, 2025):

Ever since I came across the same situation and after reading this thread, I started using the right arrow key instead of the Tab key. The Tab key seems more intuitive for an "autocomplete" feature.

I believe that this issue, given the situation, is a "can't fix", and the solution is just to get used to using the right arrow (or the End key) rather than the Tab key.

@JohnRDOrazio commented on GitHub (Mar 7, 2025): Ever since I came across the same situation and after reading this thread, I started using the right arrow key instead of the Tab key. The Tab key seems more intuitive for an "autocomplete" feature. I believe that this issue, given the situation, is a "can't fix", and the solution is just to get used to using the right arrow (or the End key) rather than the Tab key.
Author
Owner

@dwymark-celestron commented on GitHub (Mar 10, 2025):

@DHowett yes, I agree with that description of what is happening. I've dug into the issue deeper since I commented last, and I have a suggestion for anyone else who has a deeply ingrained habit of pressing TAB for completions.

You can completely prevent the TAB completion search from happening in the isearch context with a simple change to readline's configuration .inputrc. First, open or create your .inputrc file in your home directory:

nano ~/.inputrc

Add the line below to override the search terminators list to include TAB:

set isearch-terminators "\033\012\011"

Note that the default isearch-terminators are "\033\012", which is to say ESC and Ctrl+J.

This configuration change ensures that bash immediately terminates the interactive search whenever the TAB key is pressed (tab being \011 in octal). This is different from the default behavior, which is for the TAB key to be detected as a control character in this branch in lib/readline/isearch.c in the bash source:

  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
    {
      if (cxt->lastc >= 0 && (cxt->mb[0] && cxt->mb[1] == '\0') && ENDSRCH_CHAR (cxt->lastc))
	{
	  /* This sets rl_pending_input to LASTC; it will be picked up the next
	     time rl_read_key is called. */
	  rl_execute_next (cxt->lastc);
	  return (0);
	}
    }

The rl_execute_next (cxt->lastc); line is what ensures that the control character (TAB in this case) causes any associated behaviors to be executed as usual after the isearch terminates. With the addition of TAB as an isearch-terminator, this branch is never hit, and instead isearch terminates as below:

  /* The characters in isearch_terminators (set from the user-settable
     variable isearch-terminators) are used to terminate the search but
     not subsequently execute the character as a command.  The default
     value is "\033\012" (ESC and C-J). */
  if (cxt->lastc > 0 && strchr (cxt->search_terminators, cxt->lastc))
    {
      /* ESC still terminates the search, but if there is pending
	 input or if input arrives within 0.1 seconds (on systems
	 with select(2)) it is used as a prefix character
	 with rl_execute_next.  WATCH OUT FOR THIS!  This is intended
	 to allow the arrow keys to be used like ^F and ^B are used
	 to terminate the search and execute the movement command.
	 XXX - since _rl_input_available depends on the application-
	 settable keyboard timeout value, this could alternatively
	 use _rl_input_queued(100000) */
      if (cxt->lastc == ESC && (_rl_pushed_input_available () || _rl_input_available ()))
	rl_execute_next (ESC);
      return (0);

Hope this is helpful for someone. Note that you need to restart bash after making the configuration change for it to come into effect.

@dwymark-celestron commented on GitHub (Mar 10, 2025): @DHowett yes, I agree with that description of what is happening. I've dug into the issue deeper since I commented last, and I have a suggestion for anyone else who has a deeply ingrained habit of pressing TAB for completions. You can completely prevent the TAB completion search from happening in the isearch context with a simple change to `readline`'s configuration `.inputrc`. First, open or create your `.inputrc` file in your home directory: ```shell nano ~/.inputrc ``` Add the line below to override the search terminators list to include TAB: ``` set isearch-terminators "\033\012\011" ``` Note that the default isearch-terminators are "\033\012", which is to say ESC and Ctrl+J. This configuration change ensures that bash **immediately** terminates the interactive search whenever the TAB key is pressed (tab being `\011` in octal). This is different from the default behavior, which is for the TAB key to be detected as a control character in this branch in `lib/readline/isearch.c` in the bash source: ```C if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { if (cxt->lastc >= 0 && (cxt->mb[0] && cxt->mb[1] == '\0') && ENDSRCH_CHAR (cxt->lastc)) { /* This sets rl_pending_input to LASTC; it will be picked up the next time rl_read_key is called. */ rl_execute_next (cxt->lastc); return (0); } } ``` The `rl_execute_next (cxt->lastc);` line is what ensures that the control character (TAB in this case) causes any associated behaviors to be executed as usual after the isearch terminates. With the addition of TAB as an isearch-terminator, this branch is never hit, and instead isearch terminates as below: ```C /* The characters in isearch_terminators (set from the user-settable variable isearch-terminators) are used to terminate the search but not subsequently execute the character as a command. The default value is "\033\012" (ESC and C-J). */ if (cxt->lastc > 0 && strchr (cxt->search_terminators, cxt->lastc)) { /* ESC still terminates the search, but if there is pending input or if input arrives within 0.1 seconds (on systems with select(2)) it is used as a prefix character with rl_execute_next. WATCH OUT FOR THIS! This is intended to allow the arrow keys to be used like ^F and ^B are used to terminate the search and execute the movement command. XXX - since _rl_input_available depends on the application- settable keyboard timeout value, this could alternatively use _rl_input_queued(100000) */ if (cxt->lastc == ESC && (_rl_pushed_input_available () || _rl_input_available ())) rl_execute_next (ESC); return (0); ``` Hope this is helpful for someone. Note that you need to restart bash after making the configuration change for it to come into effect.
Author
Owner

@derekthesnake commented on GitHub (Mar 25, 2025):

What is the normal way to select a result from reverse-i-search?

@DHowett @JL102 I finally have a definitive answer to this. readline is what handles the reverse searching, and from the man page:

isearch-terminators (‘‘C-[ C-J'')
              The  string  of  characters  that  should  terminate an incremental
              search without subsequently executing the character as  a  command.
              If this variable has not been given a value, the characters ESC and
              C-J will terminate an incremental search.

So you could theoretically put set isearch-terminators "\C-[\C-J\t" in your .inputrc to preserve the normal terminators and not have TAB begin completion. It works in my testing (doesn't trigger completion), but I no longer use WSL so I can't confirm if it solves the problem.

@derekthesnake commented on GitHub (Mar 25, 2025): > What **is** the normal way to select a result from `reverse-i-search`? @DHowett @JL102 I finally have a definitive answer to this. readline is what handles the reverse searching, and from the man page: ``` isearch-terminators (‘‘C-[ C-J'') The string of characters that should terminate an incremental search without subsequently executing the character as a command. If this variable has not been given a value, the characters ESC and C-J will terminate an incremental search. ``` So you could theoretically put `set isearch-terminators "\C-[\C-J\t"` in your .inputrc to preserve the normal terminators and not have TAB begin completion. It works in my testing (doesn't trigger completion), but I no longer use WSL so I can't confirm if it solves the problem.
Author
Owner

@dwymark-celestron commented on GitHub (Apr 8, 2025):

It does solve the problem to add tab to the inputrc, as I suggested above. I daily drive this configuration on WSL :)

@dwymark-celestron commented on GitHub (Apr 8, 2025): It does solve the problem to add tab to the inputrc, as I suggested above. I daily drive this configuration on WSL :)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#19233