Search code examples
bashautocompletegetopts

Enable autocomplete for parsed arguments in getopts


I have a bash script that uses getopts to parse command line arguments. One of the arguments, -l <name> is directed to an if statement that determines certain settings. Is it possible to have autocomplete work in the command line for entering the <name> parameter?

Here is the command line parsing part (getopts) of my script:

while getopts 'l:r:m:?h' c
do
  case $c in
    l) 
        library=$OPTARG 
        ;;
    r)  
        rename_config=$OPTARG 
        ;;
    m)  
        align_mm=$OPTARG
        ;;  
    h|?) usage 
        ;;
  esac
done

The library option (-l) refers to this part of the script:

if [ $library = "bassik" ];
    then
        read_mod="clip"
        clip_seq="GTTTAAGAGCTAAGCTGGAAACAGCATAGCAA"
        echo "Bassik library selected"
elif [ $library = "moffat_tko1" ];
    then
        read_mod="trim"
        sg_length=20    
        echo "Moffat TKO1 library selected"
elif [ $library = "sabatini" ];
    then
        read_mod="trim"
        sg_length=20    
        echo "Sabatini library selected"
fi

The part where the auto-completion should work are for "bassik", "moffat_tko1", and "sabatini" parameters. So far, I have tried just hitting <TAB> right after ./script.sh -l, but that does not work. I have googled it, but could not find anything that fits my situation (not sure also how to call this, new to bash).


Solution

  • First I copied your script snippet in a file called auto.sh and set the execution permission on it:

    #!/bin/bash
    
    while getopts 'l:r:m:?h' c
    do
      case $c in
        l) 
            library=$OPTARG 
            ;;
        r)  
            rename_config=$OPTARG 
            ;;
        m)  
            align_mm=$OPTARG
            ;;  
        h|?) usage 
            ;;
      esac
    done
    
    
    if [ $library = "bassik" ];
        then
            read_mod="clip"
            clip_seq="GTTTAAGAGCTAAGCTGGAAACAGCATAGCAA"
            echo "Bassik library selected"
    elif [ $library = "moffat_tko1" ];
        then
            read_mod="trim"
            sg_length=20    
            echo "Moffat TKO1 library selected"
    elif [ $library = "sabatini" ];
        then
            read_mod="trim"
            sg_length=20    
            echo "Sabatini library selected"
    fi
    

    Then, to set up an auto-completion for the -l option, you can begin with those basics steps (this can be future enhanced):

    1. Create a completion script (e.g. ./auto-complete.sh) which contains the libs function to be called upon completion request (-F parameter of complete command). The function triggers the display of the library names (content of COMPREPLY array variable) if -l option is the word preceding the completion place ($3 argument):

    function libs()
    {
      # $1 is the name of the command 
      # $2 is the word being completed
      # $3 is the word preceding the word being completed
    
      case $3 in
        -l) COMPREPLY+=("bassi")
            COMPREPLY+=("moffat_tko1")
            COMPREPLY+=("sabatini");;
      esac
    }
    
    complete -F libs auto.sh
    

    2. Source the script in your local shell:

    $ source ./auto-complete.sh
    

    3. Launch the shell script and type TAB key twice after a space behind the -l option:

    $ ./auto.sh -l <tab><tab>
    bassik       moffat_tko1  sabatini
    $ ./auto.sh  -l bassik
    Bassik library selected
    

    4. The preceding systematically lists all the choices when you type TAB key. To have a more accurate completion when typing the first letters, the completion script can be enhanced to use compgen command:

    function libs()
    {
      # $1 is the name of the command 
      # $2 is the word being completed
      # $3 is the word preceding the word being completed
    
      case $3 in
        -l) COMPREPLY=($(compgen -W "bassik moffat_tko1 sabatini" "${COMP_WORDS[$COMP_CWORD]}"));;
      esac
    }
    
    complete -F libs auto.sh