2

I like to have shell completion for as many commands as possible. I write a fair amount of shell-scripts that take a lot of different parameters, and it's a life-saver to have the completion just work. I used to use zsh quite a bit, and there it was reasonably easy to write completion scripts. But for various reasons (not all of them good, admittedly) I'm now using bash everywhere.

Writing bash completion scripts is a nightmare, and it gives rise to another script that has to be updated. However - bash-completion comes with a ready-made completion _longopt which will execute a command with --help and parse the output, generating autocompletion that's significantly better than nothing.

I have been trying to write my scripts in order to take advantage of this, but so far mostly through trial-and-error (frankly, mostly error). Thus my question:

What should the output of <command> --help look like, in order for the bash-completion _longopt to work properly?

I've been looking at the sources - but, frankly, it's not much help.

2
  • 1
    I don't know about _longopt, but you can pipe the --help output into complgen scrape to generate a bash completion script.
    – Devon
    Commented Apr 30 at 10:09
  • Thanks @Devon. That looks interesting. But it appears that it only extracts the initial -<x>, --<xyz> together with the description, and doesn't do anything else.
    – Popup
    Commented Apr 30 at 13:52

1 Answer 1

0

Not a complete answer, but this is a step in the right direction.

This is a basic shell script that can be used with complete -F _longopt to autocomplete:

#!/bin/bash -e

usage() {
  echo "Usage:
$0
  -f, --file=FILE      some kind of file (mandatory)
  -d, --dir DIRECTORY  directory (optional)
  -h, --help           this text
      [--opt]          optional parameter

   (To use bash completion: complete -F _longopt $0 )"
}
OPTIONS=f:d:ho
LONGOPTS=file:,dir:,help,opt
PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@")
if [[ $? -ne 0 ]]; then
  # e.g. return value is 1
  #  then getopt has complained about wrong arguments to stdout
  exit 2
fi
# read getopt’s output this way to handle the quoting right:
eval set -- "$PARSED"

FILE=""
DIR=""
OPTIONAL=""

while true; do
  case "$1" in
    -f | --file)
      FILE=$2
      shift
      shift
      ;;
    -d | --dir)
      DIR=$2
      shift
      shift
      ;;
    --opt)
      OPTIONAL="yes"
      shift
      ;;
    -h | --help)
      usage
      exit 0
      ;;
    --)
      shift
      break
      ;;
    *)
      echo "internal getopt error"
      exit 1
      ;;
  esac
done

This will autocomplete the argument -f or --file with a mandatory filename and -d or --dir with an optional directory. I'm not sure if there are other classes (usernames, ip addresses, URLs, executables etc), nor how to narrow down to certain types of files. (Optional parameters need some more handling in getopts.)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .