Come posso aggiungere un metodo di aiuto a uno script di shell?


Risposte:


173

ecco un esempio per bash:

usage="$(basename "$0") [-h] [-s n] -- program to calculate the answer to life, the universe and everything

where:
    -h  show this help text
    -s  set the seed value (default: 42)"

seed=42
while getopts ':hs:' option; do
  case "$option" in
    h) echo "$usage"
       exit
       ;;
    s) seed=$OPTARG
       ;;
    :) printf "missing argument for -%s\n" "$OPTARG" >&2
       echo "$usage" >&2
       exit 1
       ;;
   \?) printf "illegal option: -%s\n" "$OPTARG" >&2
       echo "$usage" >&2
       exit 1
       ;;
  esac
done
shift $((OPTIND - 1))

Per usarlo all'interno di una funzione:

  • utilizzare "$FUNCNAME"invece di$(basename "$0")
  • aggiungere local OPTIND OPTARGprima di chiamaregetopts

1
Sto provando questo all'interno di una funzione, ma quando provo ad eseguire la funzione ottengo questo errore "basename: opzione non valida - 'b'". Sembra che stia cercando di passare "-bash" al basenametrattino iniziale.
Morgan Estes,

5
all'interno di una funzione "$FUNCNAME"non usare "$0". Inoltre, aggiungilocal OPTIND OPTARG
glenn jackman il

Grazie. FUNCNAMElavori. Ho tutte le mie funzioni all'interno di un singolo file, quindi questo è perfetto per estenderle in qualcosa di utile per gli altri.
Morgan Estes,

5
@sigur, assicurati di citare "$usage" ogni luogo in cui lo usi.
Glenn Jackman,

1
A cosa serve shift $((OPTIND - 1))?
hpaknia,

45

Il primo argomento di uno script di shell è disponibile come variabile $1, quindi l'implementazione più semplice sarebbe

if [ "$1" == "-h" ]; then
  echo "Usage: `basename $0` [somestuff]"
  exit 0
fi

Ma cosa ha detto anubhava.


Grazie @MarkBooth, errore di battitura corretto (più il miglioramento racchiuso tra virgolette)
seb

Dovresti prendere l'abitudine di racchiudere if in [[]] per i condizionali per evitare un cattivo analisi di una variabile, fonte: github.com/bahamas10/bash-style-guide#bashisms
JREAM

2
Sì, sebbene l'OP non abbia specificato bash ed [è la versione conforme a POSIX.
SEB

Nota: per l'uso all'interno function: è necessario sostituirlo exit 0con returnse non si desidera terminare la shell dopo aver eseguito la funzione. (L'ho già fatto prima 😂)
Illuminatore

29

ecco una parte che lo uso per avviare un server VNC

#!/bin/bash
start() {
echo "Starting vnc server with $resolution on Display $display"
#your execute command here mine is below
#vncserver :$display -geometry $resolution
}

stop() {
echo "Killing vncserver on display $display"
#vncserver -kill :$display
}

#########################
# The command line help #
#########################
display_help() {
    echo "Usage: $0 [option...] {start|stop|restart}" >&2
    echo
    echo "   -r, --resolution           run with the given resolution WxH"
    echo "   -d, --display              Set on which display to host on "
    echo
    # echo some stuff here for the -a or --add-options 
    exit 1
}

################################
# Check if parameters options  #
# are given on the commandline #
################################
while :
do
    case "$1" in
      -r | --resolution)
          if [ $# -ne 0 ]; then
            resolution="$2"   # You may want to check validity of $2
          fi
          shift 2
          ;;
      -h | --help)
          display_help  # Call your function
          exit 0
          ;;
      -d | --display)
          display="$2"
           shift 2
           ;;

      -a | --add-options)
          # do something here call function
          # and write it in your help function display_help()
           shift 2
           ;;

      --) # End of all options
          shift
          break
          ;;
      -*)
          echo "Error: Unknown option: $1" >&2
          ## or call function display_help
          exit 1 
          ;;
      *)  # No more options
          break
          ;;
    esac
done

###################### 
# Check if parameter #
# is set too execute #
######################
case "$1" in
  start)
    start # calling function start()
    ;;
  stop)
    stop # calling function stop()
    ;;
  restart)
    stop  # calling function stop()
    start # calling function start()
    ;;
  *)
#    echo "Usage: $0 {start|stop|restart}" >&2
     display_help

     exit 1
     ;;
esac

È un po 'strano che ho inserito il riavvio e il riavvio in un caso separato, ma dovrebbe funzionare


se dai un'opzione vuota a -d; non sarà un ciclo infinito?
zerobane,

Perché si esce da 1 nella funzione di supporto?
jeantimex,

17

Per una soluzione rapida a singola opzione, utilizzare if

Se hai una sola opzione da controllare e sarà sempre la prima opzione ( $1), la soluzione più semplice è una ifcon un test ( [). Per esempio:

if [ "$1" == "-h" ] ; then
    echo "Usage: `basename $0` [-h]"
    exit 0
fi

Si noti che per la compatibilità posix =funzionerà anche ==.

Perché citare $1?

Il motivo $1per cui è necessario racchiuderlo tra virgolette è che se non esiste, $1la shell tenterà di funzionare if [ == "-h" ]e fallire perché ==è stato dato un solo argomento quando se ne aspettava due:

$ [ == "-h" ]
bash: [: ==: unary operator expected

Per qualsiasi uso più complesso getoptogetopts

Come suggerito da altri , se hai più di una singola opzione o hai bisogno della tua opzione per accettare un argomento, allora dovresti assolutamente optare per la complessità aggiuntiva dell'uso getopts.

Come riferimento rapido, mi piace il tutorial su 60 secondi getopts .

Potresti anche considerare il getoptprogramma invece della shell integrata getopts. Consente l'uso di opzioni lunghe e opzioni dopo argomenti non di opzione (ad es. foo a b c --verboseAnziché solo foo -v a b c). Questa risposta StackOverflow spiega come usare GNU getopt.

jeffbyrnes ha affermato che il collegamento originale è morto, ma per fortuna il modo in cui la macchina era stata archiviata.


Grazie! Uso felicemente getopts da un anno ormai, ma darò un'occhiata anche a getopt.
tttppp

1
Purtroppo, il link a The 60 Second getopts Tutorial è morto; sembra che bashcurescancer.com non esiste più. Ecco un link alla versione della Wayback Machine .
jeffbyrnes,


-1

penso che puoi usare case per questo ...

case $1 in 
 -h) echo $usage ;; 
  h) echo $usage ;;
help) echo $usage ;;
esac
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.