2

Here's a shell script that does some stuff according to with what parameter it was called:

if [ $1 = "-add" ] 
then
    ...
elif [ $1 = "-remove" ]
    ...
else
    ...
fi

A script is an executable one (a link to it was created in the /usr/bin directory). So, I can call it from shell by specifying the link name added in /usr/bin.

What I want, is auto-detecting the possible arguments of script (in my case they are -add, -remove) during it calling. It means that when I'll type a command, related to script calling, then type -re and press a tab button it will suggest that it's -remove and autofill it for me.

How the arguments need to be defined to reach that?

Tried to create aliases in shell config file or few links in /usr/bin directory for all possible inputs and it was working fine, but I don't think it's a best solution for that.

user12345423
  • 140
  • 1
  • 1
  • 9
  • 3
    Google for "bash completion". – choroba Jul 28 '14 at 09:42
  • 1
    Auto-detecting arguments of binaries or scripts is generally not possible. You may let the shell expect it instead with bash completion. – konsolebox Jul 28 '14 at 09:44
  • There may be a way to let bash completion system communicate with the script through an invisible argument but I wouldn't want digging into such complexity. Just a tip. – konsolebox Jul 28 '14 at 09:46
  • possible duplicate of [Auto-complete command line arguments](http://stackoverflow.com/questions/3690655/auto-complete-command-line-arguments) – Aserre Jul 28 '14 at 10:03
  • thanks for a quick reply, now I know where to dig – user12345423 Jul 28 '14 at 12:37

2 Answers2

4

While it does require some configuration outside of your script, adding autocomplete options is fairly easy.

Here's a simple example of a ~/.bash_completion file that adds auto completion of --add and --remove to command yourscript. In a real world case you'd probably want to generate the options by querying the script directly; they're hard coded here for simplicity.

_yourscript_complete()
{
    # list of options for your script
    local options="--add --remove"

    # current word being completed (provided by stock bash completion)
    local current_word="${COMP_WORDS[COMP_CWORD]}"

    # create list of possible matches and store to ${COMREPLY[@}}
    COMPREPLY=($(compgen -W "${options}" -- "$current_word"))
}
complete -F _yourscript_complete yourscript

Note that the ~/.bash_completion is only sourced during login, so you'll need to spawn another login shell to see your changes in action. You may need to enable sourcing of user bash_completion files on your system, too.

The result:

$ yourscript --<tab><tab>
--add     --remove
Beggarman
  • 866
  • 5
  • 7
2

It seems that bash/zsh completion is a powerful tool that can manage you shell input in the way you want.

In one of the other answers some explanations about how it works in bash were presented.

I'm a user of zsh, so, I think, it wouldn't be superfluous to show how I managed my task there:

  1. Configuring .zshrc file:

    • adding folder for your autocomplete functions:

      fpath=(~/.zsh-completions $fpath)

    • enabling zsh tab-completion system:

      autoload -U compinit & compinit

    Note: above accented lines must be added to ~/.zshrc file.

  2. Adding a function for your script:

    After configuring .zshrc file, restarting zsh and typing scriptname in it, compinit() function will list all files with underscope from $fpath and find the one with first line that matches #compdef scriptname.

    So, a new file _scriptname that will hold a function for our script must be added to ~/.zsh-completions directory. To let compinit() find this file on scriptname typing, as mentioned above, its first line must be: #compdef scriptname.

  3. Let the arguments dancing:

    For zsh there are a lot of completion functions examples in /usr/share/zsh/functions/Completion directory. By finding the appropriate one there you can configure your shell input according to your tastes. For auto-detecting the attributes (in my case they are -add and -remove) an _attributes() function in the _scriptname file could be set in the next way:

    _arguments -s \            
    '(-a --add)'{-a,--add}'[adding a new item to the basket]' \
    '(-r --remove)'{-r,--remove}'[removing an item from the basket]'
    

Eventually, after restarting zsh again, auto-detecting for scriptname is working as below:

scriptname -<TAB>   => scriptname -      
                       --add     -a  -- adding a new item to the basket                  
                       --remove  -r  -- removing an item from the basket

scriptname --a<TAB> => scriptname --add 
scriptname --r<TAB> => scriptname --remove
user12345423
  • 140
  • 1
  • 1
  • 9