4

I've used complete -W 'firstdatabase databasetwo etc' mysql to save a list of databases, so that I can autocomplete them using the mysql command.

However, in many cases I would type mysql db < /tmp/script.sql. How can I get bash to revert to traditional autocomplete (filenames) after seeing the first > or <?


Update: I pulled up a stock Ubuntu install, which comes with the bash-autocomplete package pre-installed. While simply installing that same package on our server is not an option for me, I can still learn from its implementation by examining the output of complete -p and declare. (alias -p has some cool stuff as well)

On our server, I used complete -d cd. I observe that it suffers from the same issue in that after < or >, the complete -d functionality persists. However, bash-autocomplete has a more elaborate approach which solves this issue. Learning how they solved it for cd (and a multitude of other commands) may show how to solve the same issue I'm having for mysql.

So, here is their implementation for cd: They use complete -o nospace -F _cd cd, which basically calls function _cd for the autocomplete query. Here is the function they use:

_cd ()
{ 
    local cur prev words cword;
    _init_completion || return;
    local IFS='
' i j k;
    compopt -o filenames;
    if [[ -z "${CDPATH:-}" || "$cur" == ?(.)?(.)/* ]]; then
        _filedir -d;
        return 0;
    fi;
    local -r mark_dirs=$(_rl_enabled mark-directories && echo y);
    local -r mark_symdirs=$(_rl_enabled mark-symlinked-directories && echo y);
    for i in ${CDPATH//:/'
'};
    do
        k="${#COMPREPLY[@]}";
        for j in $( compgen -d $i/$cur );
        do
            if [[ ( -n $mark_symdirs && -h $j || -n $mark_dirs && ! -h $j ) && ! -d ${j#$i/} ]]; then
                j+="/";
            fi;
            COMPREPLY[k++]=${j#$i/};
        done;
    done;
    _filedir -d;
    if [[ ${#COMPREPLY[@]} -eq 1 ]]; then
        i=${COMPREPLY[0]};
        if [[ "$i" == "$cur" && $i != "*/" ]]; then
            COMPREPLY[0]="${i}/";
        fi;
    fi;
    return 0
}

complete -o nospace -F _cd cd

Running the above code on a recent version of bash gives the desired results for cd. Now how can this be converted for mysql? (or anything I'd normally use complete -W for?)

1
  • It's not obvious to me how this code works, but I'll figure it out eventually. Feb 5, 2016 at 17:54

1 Answer 1

1

The magic is in the _init_completion function which is defined in the bash_completion file of the bash-completion package.

There's no easy way out. If you want sensible fancy completion in bash, install the bash-completion package. Then define a function:

. /etc/bash_completion
_my_mysql () {
  local cur prev words cword
  _init_completion || return
  COMPREPLY=($(compgen -W 'firstdatabase databasetwo etc' "$cur"))
}
complete -F _my_mysql mysql
2
  • That's it, thanks. For some reason I missed the fact that the _cd function didn't work by itself. I tried to install bash-completion, but the build failed on my server. I may try harder later. Thanks for the example _my_mysql function. This should save me some time once I get this stuff worked out because I imagine I'm going to have a lot more customizations moving forward. :-) Feb 6, 2016 at 1:48
  • Next thing I try will probably be to copy the finished autocomplete files from Ubuntu, and skip the make step altogether. Feb 6, 2016 at 1:54

You must log in to answer this question.

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