最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

shell - Custom bash completion obtaining from help text - Stack Overflow

programmeradmin3浏览0评论

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.

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.

Share Improve this question edited Feb 25 at 22:34 halfer 20.3k19 gold badges109 silver badges202 bronze badges asked Jan 29 at 23:30 Ramanan TRamanan T 3833 silver badges13 bronze badges 10
  • Is that really the entire contents of the dbcmd file? Why does it need the echo statement -- it could just contain the list of commands as a text file. – Barmar Commented Jan 29 at 23:42
  • Don't fet to remove the " on the last line. – Barmar Commented Jan 29 at 23:45
  • You don't describe "weird behaviour" more closely, so it's hard to tell what you mean. The if/else` block at the end of the function injects spaces, which seems unnecessary, but I don't know what the indented behaviour is. – Benjamin W. Commented Jan 29 at 23:55
  • @BenjaminW. Basically it doesn't complete the commands. it is all over the command prompt with TABs & spaces and cannot backspace and delete. Quite hard to describe. It would be easer if you use the script for completion and run dbcmd TAB TAB. This is straight forward script – Ramanan T Commented Jan 30 at 0:29
  • Not resetting IFS improves things for me. – Benjamin W. Commented Jan 30 at 2:04
 |  Show 5 more comments

2 Answers 2

Reset to default 0

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')"

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
发布评论

评论列表(0)

  1. 暂无评论