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
whilegetopts':hs:' option; docase"$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
;;
esacdoneshift $((OPTIND - 1))
Aby użyć tego wewnątrz funkcji:
użyj "$FUNCNAME"zamiast$(basename "$0")
dodaj local OPTIND OPTARGprzed zadzwonieniemgetopts
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" ]; thenecho"Usage: `basename $0` [somestuff]"exit 0
fi
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/bashstart() {
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
echoecho" -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 :
docase"$1"in
-r | --resolution)
if [ $# -ne 0 ]; then
resolution="$2"# You may want to check validity of $2fishift 2
;;
-h | --help)
display_help # Call your functionexit 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 optionsshiftbreak
;;
-*)
echo"Error: Unknown option: $1" >&2
## or call function display_helpexit 1
;;
*) # No more optionsbreak
;;
esacdone###################### # 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" ] ; thenecho"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:
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.
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.
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 .
Odpowiedzi:
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:
"$FUNCNAME"
zamiast$(basename "$0")
local OPTIND OPTARG
przed zadzwonieniemgetopts
źródło
basename
z początkowym myślnikiem."$FUNCNAME"
nie używa"$0"
. Dodaj teżlocal OPTIND OPTARG
FUNCNAME
Pracuje. Mam wszystkie moje funkcje w jednym pliku, więc jest to idealne rozwiązanie do rozszerzenia ich na coś przydatnego dla innych."$usage"
każde miejsce, w którym go używasz.shift $((OPTIND - 1))
?Pierwszy argument skryptu powłoki jest dostępny jako zmienna
$1
, więc najprostsza byłaby implementacjaif [ "$1" == "-h" ]; then echo "Usage: `basename $0` [somestuff]" exit 0 fi
Ale co powiedział Anubhava.
źródło
[
jest wersją zgodną z POSIX.function
: Należy wymienićexit 0
zereturn
jeśli nie chcesz, aby zakończyć swoją skorupę po uruchomić funkcję. (Robiłem to wcześniej 😂)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ć
źródło
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 metodaif
z 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,
$1
dla którego należy ująć w cudzysłów, jest to, że jeśli nie ma,$1
to 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ń
getopt
lubgetopts
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ć
getopt
program zamiast wbudowanej powłokigetopts
. Pozwala na użycie długich opcji i opcji po argumentach innych niż opcje (np.foo a b c --verbose
Raczej niż tylkofoo -v a b c
). Ta odpowiedź Stackoverflow wyjaśnia, jak używać GNUgetopt
.† jeffbyrnes wspomniał, że oryginalny link zgasł, ale na szczęście maszyna zarchiwizowała go.
źródło
Lepiej jest użyć funkcji bash w getopt. Proszę spojrzeć na te pytania i odpowiedzi, aby uzyskać dodatkową pomoc: Używanie getopts w skrypcie powłoki bash, aby uzyskać długie i krótkie opcje wiersza poleceń
źródło
myślę, że możesz użyć tego przypadku ...
case $1 in -h) echo $usage ;; h) echo $usage ;; help) echo $usage ;; esac
źródło