Jak mogę dodać metodę pomocy do skryptu powłoki?


Odpowiedzi:


177

oto przykład dla basha:

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))

Aby użyć tego wewnątrz funkcji:

  • użyj "$FUNCNAME"zamiast$(basename "$0")
  • dodaj local OPTIND OPTARGprzed zadzwonieniemgetopts

1
Próbuję tego wewnątrz funkcji, ale kiedy próbuję uruchomić funkcję, pojawia się komunikat o błędzie: „basename: invalid option - 'b'”. Wygląda na to, że próbuje przekazać „-bash” do basenamez początkowym myślnikiem.
Morgan Estes

5
imside funkcja "$FUNCNAME"nie używa "$0". Dodaj teżlocal OPTIND OPTARG
glenn jackman,

Dzięki. FUNCNAMEPracuje. Mam wszystkie moje funkcje w jednym pliku, więc jest to idealne rozwiązanie do rozszerzenia ich na coś przydatnego dla innych.
Morgan Estes

5
@sigur, zacytuj "$usage" każde miejsce, w którym go używasz.
glenn jackman

1
Do czego służy shift $((OPTIND - 1))?
hpaknia

46

Pierwszy argument skryptu powłoki jest dostępny jako zmienna $1, więc najprostsza byłaby implementacja

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

Ale co powiedział Anubhava.


Powinieneś mieć zwyczaj zawijania if w [...]] dla warunków warunkowych, aby uniknąć złego parsowania zmiennej, źródło: github.com/bahamas10/bash-style-guide#bashisms
JREAM

2
Tak, chociaż OP nie określa bash i [jest wersją zgodną z POSIX.
seb

Uwaga - W przypadku korzystania wewnątrz function: Należy wymienić exit 0ze returnjeśli nie chcesz, aby zakończyć swoją skorupę po uruchomić funkcję. (Robiłem to wcześniej 😂)
Illuminator,

29

tutaj jest część, której używam do uruchomienia serwera 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

To trochę dziwne, że umieściłem start stop restart w osobnym przypadku, ale powinno działać


jeśli dasz pustą opcję -d; czy nie będzie to nieskończona pętla?
zerobane

Dlaczego wychodzisz z 1 w funkcji pomocniczej?
jeantimex

17

Aby uzyskać szybkie rozwiązanie z jedną opcją, użyj if

Jeśli masz tylko jedną opcję do sprawdzenia i zawsze będzie to pierwsza opcja ( $1), najprostszym rozwiązaniem jest metoda ifz testem ( [). Na przykład:

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

Zauważ, że dla kompatybilności z posix =zadziała również ==.

Dlaczego cytować $1?

Powodem, $1dla którego należy ująć w cudzysłów, jest to, że jeśli nie ma, $1to powłoka spróbuje uruchomić się if [ == "-h" ]i zawiedzie, ponieważ ==otrzymała tylko jeden argument, gdy oczekiwała dwóch:

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

Do bardziej złożonych zastosowań getoptlubgetopts

Jak sugerowano przez innych , jeśli masz więcej niż jedną opcję prostego lub potrzebujesz opcję przyjąć argumentu, to powinno się iść do dodatkowej złożoności użyciu getopts.

Krótko mówiąc, podoba mi się samouczek dotyczący 60 sekund getopts .

Możesz także rozważyć getoptprogram zamiast wbudowanej powłoki getopts. Pozwala na użycie długich opcji i opcji po argumentach innych niż opcje (np. foo a b c --verboseRaczej niż tylko foo -v a b c). Ta odpowiedź Stackoverflow wyjaśnia, jak używać GNU getopt.

jeffbyrnes wspomniał, że oryginalny link zgasł, ale na szczęście maszyna zarchiwizowała go.


Dzięki! Od roku szczęśliwie używam getopts, ale przyjrzę się też getopt.
tttppp

1
Niestety, link do samouczka The 60 Second getopts jest martwy; wygląda na to, że bashcurescancer.com już nie istnieje. Oto link do wersji Wayback Machine .
jeffbyrnes


-1

myślę, że możesz użyć tego przypadku ...

case $1 in 
 -h) echo $usage ;; 
  h) echo $usage ;;
help) echo $usage ;;
esac
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.