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?)

  • It's not obvious to me how this code works, but I'll figure it out eventually. – Bryan Field Feb 5 '16 at 17:54
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
  • 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. :-) – Bryan Field Feb 6 '16 at 1:48
  • Next thing I try will probably be to copy the finished autocomplete files from Ubuntu, and skip the make step altogether. – Bryan Field Feb 6 '16 at 1:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.