Ramanan T
Ramanan T

Reputation: 383

Custom bash completion obtaining from help text

For some reason Bash completion doesn't work when I obtain from help text.

This is my C++ file compiled and placed as dbcmd executable file in one of the PATHs:

$ cat dbcmd.cpp
#include <iostream>
#include <string>
#include <vector>

static void usage()
{
        std::cerr << "Usage: dbcmd [<command> [<command-args>]]\n";
        std::cerr << "Commands:\n";

        std::vector<std::string> commands;

        commands.push_back("backup");
        commands.push_back("db-backup");
        commands.push_back("db-purge");
        commands.push_back("load");
        commands.push_back("debug");
        commands.push_back("analyze");
        commands.push_back("cycle");
        commands.push_back("endday");
        commands.push_back("gendbset");
        commands.push_back("help");
        commands.push_back("perform");
        commands.push_back("print");
        commands.push_back("remove");
        commands.push_back("restart");
        commands.push_back("dump");
        commands.push_back("start");
        commands.push_back("status");
        commands.push_back("stop");
        commands.push_back("tables");
        commands.push_back("info");
        commands.push_back("update");
        for (auto command: commands)
                std::cerr << "  " << command << "\n";
}

int main()
{
        usage();
        return 0;
}

And this is my Bash completion script (credit):

$ cat dbcmd_completion.bash
#/usr/bin/env bash
_dbcmd_completions()
{
        if [ "${#COMP_WORDS[@]}" != "2" ]; then
                return
        fi

        local IFS=$'\n'
        local list_var="$(dbcmd|awk -F '\t' '{printf("%s", $1)}'|sed 's/.*://'|sed 's/^\s.//'|sed 's/\s\+/ /g')"
        local suggestions=($(compgen -W "$list_var" -- "${COMP_WORDS[1]}"))

        if [ "${#suggestions[@]}" == "1" ]; then
                local number="${suggestions[0]/%\ */}"
                COMPREPLY=("$number")
        else
                for i in "${!suggestions[@]}"; do
                        suggestions[$i]="$(printf '%*s' "-$COLUMNS"  "${suggestions[$i]}")"
                done
                COMPREPLY=("${suggestions[@]}")
        fi
}

_dothis_completions()
{
        if [ "${#COMP_WORDS[@]}" != "2" ]; then
                return
        fi
        local list_var="backup db-backup db-purge load debug analyze cycle endday gendbset help perform print remove restart dump start status stop tables info update"
        local suggestions=($(compgen -W "$list_var" -- "${COMP_WORDS[1]}"))

        if [ "${#suggestions[@]}" == "1" ]; then
                local number="${suggestions[0]/%\ */}"
                COMPREPLY=("$number")
        else
                for i in "${!suggestions[@]}"; do
                        suggestions[$i]="$(printf '%*s' "-$COLUMNS"  "${suggestions[$i]}")"
                done
                COMPREPLY=("${suggestions[@]}")
        fi
}
#complete -F _dothis_completions dbcmd
complete -F _dbcmd_completions dbcmd

When I uncomment and use _dothis_completions it works perfectly, but _dbcmd_completions--which obtains completion list from help text of dbcmd--doesn't work. When TAB is pressed it produces weird behaviour.

When you execute echo $list_var basically in both of the functions produce the same result. Why doesn't Bash completion like awk/sed produced result. This is on RH 9.

Upvotes: 0

Views: 115

Answers (2)

Ramanan T
Ramanan T

Reputation: 383

Finally able to solve this. Things to note are:

  1. Removed IFS
  2. redirecting stderr output to stdout

Working script is:

$ cat dbcmd_completion.bash
#/usr/bin/env bash
_dbcmd_completions()
{
        if [ "${#COMP_WORDS[@]}" != "2" ]; then
                return
        fi
        local list_var="$(dbcmd 2>&1|awk -F '\t' '{printf("%s", $1)}'|sed 's/.*://'|sed 's/^\s.//'|sed 's/\s\+/ /g')"
        local suggestions=($(compgen -W "$list_var" -- "${COMP_WORDS[1]}"))
        if [ "${#suggestions[@]}" == "1" ]; then
                local number="${suggestions[0]/%\ */}"
                COMPREPLY=("$number")
        else
                for i in "${!suggestions[@]}"; do
                        suggestions[$i]="$(printf '%*s' "-$COLUMNS"  "${suggestions[$i]}")"
                done
                COMPREPLY=("${suggestions[@]}")
        fi
}

complete -F _dbcmd_completions dbcmd

Upvotes: 0

Philippe
Philippe

Reputation: 26727

It seems using source works :

local list_var="$(source dbcmd|awk -F '\t' '{printf("%s", $1)}'|sed 's/.*://'|sed 's/^\s.//'|sed 's/\s\+/ /g')"

Upvotes: 0

Related Questions