Jak mogę wykryć, że żadne opcje nie zostały przekazane za pomocą getopts?

19

Mam ten kod -

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
done
print 'hi'$name

Kiedy uruchamiam bash getoptDemos.sh(bez opcji), drukuje hizamiast wywoływać funkcję usage. Wywołuje użycie, gdy podano opcje inne niż w, h i l. To nie może działać, gdy nie określono żadnych opcji.

Próbowałem za pomocą ?, \?, :w miejscu *, ale nie mogę osiągnąć to, co chciałem. Mam na myśli, że wszystko wskazuje docsna getoptto, aby używać ?.

Co ja robię źle?

Hussain Tamboli
źródło
Pod jaką powłoką go uruchamiasz?
Julian
Używam go pod/bin/bash
Hussain Tamboli,

Odpowiedzi:

15

Kiedy uruchomisz ten skrypt bez żadnych opcji, getopt zwróci false, więc w ogóle nie wejdzie w pętlę. Po prostu spadnie do wydruku - czy to ksh / zsh?

Jeśli musisz mieć opcję, najlepiej jest przetestować $ name po pętli.

if [ -z "$name" ]
then
   usage
   exit
fi

Ale upewnij się, że $namebył pusty przed wywołaniem getopts(ponieważ $namew środowisku mogło być otoczenie, które powłoka otrzymywała podczas uruchamiania)

unset name

(przed getoptspętlą)

juliański
źródło
Nie. jego uderzenie. Jak więc osiągnąć to, co chcę - obsłużyć no argumentwarunek za pomocą bash.
Hussain Tamboli,
Jeśli chcesz obowiązkową opcję, nie sądzę, że jest to możliwe - prawdopodobnie dlatego są nazywane opcjami :) Możesz jednak przetestować $ name po pętli, aby upewnić się, że została ustawiona. if [-z "$ name"]; następnie użycie; wyjście ; fi
Julian
dzięki. powyższy kod naprawdę pomógł. Szkoda, getoptsże nie ma takiego przepisu. Co gorsze, to nie mogę cię głosować.
Hussain Tamboli,
co jeśli uruchomiłem inną powłokę? zsh, sh. czy jakakolwiek powłoka inna niż bash zajmuje się tym warunkiem?
Hussain Tamboli,
20

getoptsprzetwarza opcje kolejno. To jest jego praca. Jeśli zdarzy się, że użytkownik nie przekaże żadnej opcji, pierwsze wywołanie metody getoptskończy pętlę while.

Jeśli żadna z opcji nie przyjmuje argumentu, wartość OPTINDwskazuje, ile opcji zostało przekazanych. Ogólnie rzecz biorąc, OPTINDjest to liczba argumentów, które są opcjami lub argumentami opcji, w przeciwieństwie do argumentów innych niż opcje (operandów).

while getopts …; do …; done
if [ $OPTIND -eq 1 ]; then echo "No options were passed"; fi
shift $((OPTIND-1))
echo "$# non-option arguments"

W każdym razie nie próbujesz ustalić, czy nie było żadnych opcji, ale czy żadna z nameopcji -set nie została przekazana. Więc sprawdź, czy namejest rozbrojony (i staraj się go najpierw rozbroić) .

Gilles „SO- przestań być zły”
źródło
1
dzięki. +1 dla ciebie. kiedy wstawiam 3 ostatnie wiersze twojego kodu do sample.sh i uruchamiam bash sample.sh -abc file.txtto daje - 1 non-option arguments. jak mogę dowiedzieć się, ile opcji zostało podanych. (tutaj 3)
Hussain Tamboli
1
Dziwne, że nikt nie skomentował tego drobnego błędu - jeśli nie podano żadnych opcji, OPTIND będzie wynosił 1 po tej pętli „while getopts ...”. Zatem sprawdzenie jeśli powinno sprawdzić równość z 1, a nie zerem.
Daniel
4

Jeśli twój skrypt musi otrzymać argumenty opcji, umieść ten blok na początku (przed getops).

if [[ ! $@ =~ ^\-.+ ]]
then
  #display_help;
fi

Blok sprawdza, czy łańcuch parametrów nie zaczyna się od -symbolu, co wskazuje, że pierwszy parametr nie jest argumentem opcji.

Mcounad
źródło
2

Sprawdziłbym to za pomocą zmiennej. Jeśli getopts nigdy nie przejdzie pętli w przypadku braku argumentu, możesz użyć tego na przykład w następujący sposób:

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}

no_args="true"
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
    no_args="false"
done

[[ "$no_args" == "true" ]] && { usage; exit 1; }

print 'hi'$name
Imre Kneifel
źródło
0

Tuż przed getoptsblokiem sprawdź, czy $1(pierwszy argument / opcja przekazany w wierszu poleceń) jest pusty. Jeśli tak, wydrukuj komunikat o użytkowaniu i wyjdź (lub uruchom funkcję „brak opcji”, jeśli jesteś anarchistą), w przeciwnym razie pozwól getoptsprzeanalizować opcje jak zwykle.

Powodem, dla którego ta funkcja nie jest zawarta w getopts, jest to, że można ją już wykonać w trybie bash za pomocą „if-else”. Przykład:

if [[ $1 == "" ]]; then
    Your_Usage_Function;
    exit;
else
   #parse options with getopts code block here;
fi

Ma sens?

codrcodz
źródło