Following is what i would like to have. When the tab completion is ambiguous, and bash prints the list of possibilities. I would like it to colour the next character I should press inside every word in the list.

Following is what i have done so far. In my .bashrc i have defined the following function and have called the complete command

_colourunique() {
    local word=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=($(compgen -f -- "${word}"))
    if [[ "$word" ]] && [[ ${#COMPREPLY[@]} -gt 1 ]]; then
        local  w
        local  i=0
        for ((i=0;i<${#COMPREPLY[@]};i++)) ; do

complete -D -F _colourunique

But it is not working... When i type

ls D[TAB]

It autocompletes as

ls D\033[91m

Instead of listing the possibilities Documents, Desktop etc. What could be going wrong here? Or is there some other direct way to accomplish this?


I think i understand what is happening here. Since i add \033[91m to every word in COMPREPLY, bash sees this part is common to all, and autocompletes that common term into the command prompt itself. (instead of simply printing the list)

So I don't think this method of editing COMPREPLY array is the way to do it. Is there any other method?


To preserve the uniqness, i tried to add a $i and \b in the string.


Now it prints the possible tab completions as following.

D0\b\033[91mo\033[0mwnloads  D1\b\033[91me\033[0msktop

Which means, the list is printed as such. There is no evaluation of \b or \033[91m characters. :-(


Since the replies looks like, there is no way to accomplish what i want in bash (unless i shift to zsh). I decided to settle for another option. I will try to append the next unique key stroke to end of every word, so that it stands out.

Following is the code so far.

SanitiseString () {
    local String="$1"
    local j
    for j in \\ \! \@ \# \$ \% \^ \& \* \( \) \+ \{ \[ \] \} \| \; \: \" \' \, \? \ ; do
    echo "$String"

_colourunique() {
    local word=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=($(compgen -f -- "${word}"))
    if [[ "$word" ]] ; then
        local  w
        local  i=0
        for ((i=0;i<${#COMPREPLY[@]};i++)) ; do
            w=$(SanitiseString "$w")
            if  [[ ${#COMPREPLY[@]} -gt 1 ]] ; then
                COMPREPLY[$i]="$w :${w:n:1}"

complete -D -F _colourunique

This will print the options with the next unique keystroke separated by :

But the code still has two irritating issues. which i have to solve

  1. It no longer appends the / at the end of autocompleted directories
  2. It no longer does the intelligent spacing after the auto complete.

Any suggestions?

  • I don't think you can do what you are attempting. The escapes sequences used to format the output should not actually be part of the output, but bash simply doesn't provide a hook for custom formatting of the possible completions.
    – chepner
    Commented Apr 6, 2014 at 13:20
  • 1
    The easy answer is to switch to zsh, where this is a configuration option. Commented Apr 6, 2014 at 22:50
  • Since it looks like I cannot do what i want in bash. I am trying to do a different thing instead. I have added an update which appends the next unique keyword separated by : to the list to print.
    – indiajoe
    Commented Apr 7, 2014 at 18:47

2 Answers 2


Although this is not exactly what you asked for, I decided to post this answer because originally I had the same idea as you, but in the end I solve it like this and I find it even better than coloring.

One can set this option for GNU readline library:

completion-prefix-display-length The length in characters of the common prefix of a list of possible completions that is displayed without modification. When set to a value greater than zero, common prefixes longer than this value are replaced with an ellipsis when displaying possible completions.

So for example this line in ~/.inputrc:

set completion-prefix-display-length 2

mades the trick too (when the common prefix is longer than two characters).


my .c is not so hot, but from reading around inside http://git.savannah.gnu.org/cgit/bash.git/snapshot/bash-master.tar.gz, it looks to me like COMPREPLY is nothing more than non-actioned text data. iow, even getting an Escape in there correctly ends up being printed as a non-magical/non-special representation of the characters we use to express them.

like \033 or \e isn't the single character "Escape", but the four or two characters of backslashes and zeros, threes, and Es.

I poked with various iterations of printf/echo/eval before diving into the .c to see how it actually handled the values in COMPREPLY.

might be wrong, but check strlist_print() in lib/sh/stringlist.c looks like COMPREPLY is a struct of type STRINGLIST (as defined in externs.h).

  • So what does that mean? Are you saying STRINGLIST because those are handle specially and escapes are … escaped?
    – anon
    Commented Jan 7, 2017 at 17:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .