6

I have a script that requires as an argument the name of command and arguments of that command.

So I want to write a completion function that would complete the name of the command and would complete the arguments for that command.

So I can complete the name of the command like this

if [[ "$COMP_CWORD" == 1 ]]; then
    COMPREPLY=( $( compgen -c ${COMP_WORDS[COMP_CWORD]} ))
else
    #Don't know what to write here
fi

So this will complete the first argument to list of shell commands that are available to run. And on second and other arguments I need a completion for ${COMP_WORDS[COMP_CWORD]} command.

I thought about removing first element from COMP_WORDS, decreasing COMP_CWORD by one and call a function _${COMP_WORDS[0]} with name that prefixes "_" to the command, because in many examples the function that completes a command has such name, but when I executed complete -p in bash I found that many commands are completed with functions that has different names. And as for me, such solution looks really bad.

I'm not a bash scripting guru so I just don't know where to start searching the solution.

JustAnotherCurious
  • 2,208
  • 15
  • 32
  • 2
    Check how command completion for `sudo` works... sudo takes a command & arguments to that command as completion options... Same as your script.. – anishsane Mar 24 '15 at 11:45
  • 1
    See if `complete -F _command name-of-your-script` works.. – anishsane Mar 24 '15 at 11:47
  • 1
    @anishsane Thanks. =) I forgot that sudos completion make the same behavior I need. I look at completion script and found that "_command_offset 1" does exactly what I need in else part. I'll test this for couple of days if there are some unexpected behavior and post a solution here if everything will be ok. – JustAnotherCurious Mar 24 '15 at 13:02

2 Answers2

6

Your requirement is similar to the command completion for exec or time or xargs. These commands also take a command & that command's arguments as completion options.

Checking the bash_completion option for exec:

$ complete -p exec
complete -F _command exec

You can re-use the same function _command as your completion function..

Usage:

complete -F _command your-script.sh
anishsane
  • 20,270
  • 5
  • 40
  • 73
  • Thanks, this is the easiest way to solve the task. Yesterday I just didn't understand your comment to the question. And now I see what you mean. – JustAnotherCurious Mar 25 '15 at 11:38
2

I’ve had a similar issue but my command has subcommands and global options. For example, I needed to be able to complete the following:

mycmd -o foo run ls ./Tab

To make this work, _command is insufficient. But _command_offset works well. This is also what e.g. the sudo completion uses. Here’s an example, from my implementation, which supports both short and long options with arguments:

_mycmd_completion() {
  local cur prev words cword
  _init_completion || return

  local i
  for ((i = 1; i < cword; i++)); do
    case ${words[$i]} in
      -o|--option) ((i++)) ;; # Skip option value
      -o*|--option=*) ;;
      *) break ;; # end of options
    esac
  done

  case ${words[$i]} in
    run)
      _command_offset "$((i + 1))"
      return
      ;;
    …other commands…) … ;;
  esac

  COMPREPLY=($(compgen -W '--option -o run …other commands…' -- "$cur"))
}

complete -F _mycmd_completion mycmd
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214