Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I want to create a bash completion script which recognises arguments of the form --arg and --some-arg=file.

After reading this tutorial and some examples in /usr/share/bash_completion/completions/, I've written the following script (to save time at typing some flags with Chromium):

_chromium() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    # Some interesting options
    opts="
--disable-web-security
--easy-off-store-extension-install
--incognito
--load-extension=
--pack-extension=
--pack-extension-key=
--user-data-dir=
"
    # Handle --xxxxxx=file
    if [[ ${cur} == "--"*"=" ]] ; then
        # Removed failures (is my logic OK?)
        return 0
    fi

    # Handle other options
    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
}
complete -F _chromium chromium

I saved it to ~/bash_completions/chromium, and created a symlink using sudo ln -s ~/bash_completions/chromium /usr/share/bash_completion/completions/chromium.
Then I loaded it using . /usr/share/bash_completions/completions/chromium.

Now, I'm experiencing two problems:

  • chromium --u<TAB> expands to chromium --user-data-dir=<SPACE> (I don't want the space).
  • Paths (directories and files) are not completed any more.

How can I solve these problems?

share|improve this question
    
Is switching to zsh an option? –  Gilles Nov 12 '12 at 23:36

2 Answers 2

up vote 3 down vote accepted

I have found the solution to both problems!

  1. To not append a space, use the nospace option. This can be done in two ways:

    • Pass it to the complete:
      complete -o nospace -F _chromium chromium
    • Use the compopt built-in:
      compopt -o nospace (to enable the option)
      compopt +o nospace (to disable the option)

    I found it in the Bash documentation at gnu.org, 8.7 Programmable Completion Builtins.

  2. Completion of files.
    • peterph suggested to use the -f flag with compgen). I followed that advice, and implemented it as COMPREPLY=( $(compgen -f "$cur") ). This worked fine, until I tried to complete a path containing spaces.
      On Stack Overflow, I found this answer which recommends manual creation of the completion list (without using compgen). This approach worked fine.

With aid of Bash's string manipulation (to expand ~ and deal with spaces), I constructed a bash completion scripts which meets all criteria stated in the question.

_chromium() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    # Some interesting options
    opts="
--disable-web-security
--easy-off-store-extension-install
--incognito
--load-extension=
--pack-extension=
--pack-extension-key=
--user-data-dir=
"
    # Handle --xxxxxx=
    if [[ ${prev} == "--"* && ${cur} == "=" ]] ; then
        COMPREPLY=(*)
        return 0
    fi
    # Handle --xxxxx=path
    if [[ ${prev} == '=' ]] ; then
        # Unescape space
        cur=${cur//\\ / }
        # Expand tilder to $HOME
        [[ ${cur} == "~/"* ]] && cur=${cur/\~/$HOME}
        # Show completion if path exist (and escape spaces)
        local files=("${cur}"*)
        [[ -e ${files[0]} ]] && COMPREPLY=( "${files[@]// /\ }" )
        return 0
    fi

    # Handle other options
    COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
    if [[ ${#COMPREPLY[@]} == 1 && ${COMPREPLY[0]} != "--"*"=" ]] ; then
        # If there's only one option, without =, then allow a space
        compopt +o nospace
    fi
    return 0
}
complete -o nospace -F _chromium chromium
share|improve this answer
    
Awesome answer, thanks a lot. You've saved a lot of my time. I used -f switch for file path completion, but it does not complete the / char if it is a directory... it is a small thing though. –  Jiri Kremser Mar 6 at 22:52

To complete filenames try passing -f to compgen.

I'm afraid you won't be able to get rid of the spaces after the options, since that's how completion works - once it finds a unique match, it completes it completely.

share|improve this answer
    
Thanks for the suggestion of -f. I tried it, but it does not correctly deal with spaces: The path /tmp/foo bar results in two completion entries /tmp/foo and bar. About the unwanted --arg=<SPACE>: I have found the solution to that, and posted it inthe answer below. –  Rob W Nov 13 '12 at 16:23

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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