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?


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


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


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.


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

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?

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.