Jak obsługiwać przełączniki w skrypcie powłoki?

17

Czy istnieją jakieś wbudowane narzędzia, które rozpoznają -xi --xxxxjak przełączniki, a nie argumenty, czy trzeba przejść przez wszystkie zmienne wejściowe, test na kresek, a następnie przeanalizować argumenty potem?

użytkownik394
źródło

Odpowiedzi:

16

Zastosowanie getopts.

Jest dość przenośny, jak w specyfikacji POSIX. Niestety nie obsługuje długich opcji.

Zobacz także ten getopts samouczek dzięki uprzejmości wiki bash-hackers i to pytanie z stackoverflow.

Jeśli potrzebujesz tylko krótkich opcji, typowy wzorzec użycia getopts(przy użyciu cichego raportowania błędów) to:

# process arguments "$1", "$2", ... (i.e. "$@")
while getopts "ab:" opt; do
    case $opt in
    a) aflag=true ;; # Handle -a
    b) barg=$OPTARG ;; # Handle -b argument
    \?) ;; # Handle error: unknown option or missing required argument.
    esac
done
jw013
źródło
3
Należy wspomnieć, że getoptzawsze należy zweryfikować jako GNU getopt przed użyciem, ale i tak nie należy go używać, ponieważ i tak getoptsjest bardziej przenośny (i ogólnie ładniejszy). Jeśli zrobić potrzebę, aby zadzwonić go z jakiegoś powodu nazywają go w GNU specyficzny sposób, i upewnić się, że GETOPT_COMPATIBLEnie jest w środowisku.
Chris Down,
Co robi dwukropek while getopts "ab:" opt?
user394
1
@ user394 :Po literze opcji oznacza, że ​​wymaga argumentu. A :jako pierwszy znak oznacza pomijanie komunikatów o błędach.
jw013,
22

Zakładam, że używasz bash lub podobnego. Przykład:

all=false
long=false

while getopts ":hal" option; do
  case $option in
    h) echo "usage: $0 [-h] [-a] [-l] file ..."; exit ;;
    a) all=true ;;
    l) long=true ;;
    ?) echo "error: option -$OPTARG is not implemented"; exit ;;
  esac
done

# remove the options from the positional parameters
shift $(( OPTIND - 1 ))

ls_opts=()
$all && ls_opts+=( -a )
$long && ls_opts+=( -l )

# now, do it
ls "${ls_opts[@]}" "$@"
Glenn Jackman
źródło
1
+1 za używanie +=z tablicą. Nie wiedziałem, że możesz to zrobić. Ładny!
James Sneeringer
5

Musisz napisać cykl, aby przeanalizować parametry. Rzeczywiście możesz użyć getoptspolecenia, aby zrobić to łatwo.

To prosty przykład ze getoptsstrony podręcznika:

aflag=
bflag=
while getopts ab: name
do
    case $name in
    a)    aflag=1;;
    b)    bflag=1
          bval="$OPTARG";;
    ?)    printf "Usage: %s: [-a] [-b value] args\n" $0
          exit 2;;
    esac
done
if [ ! -z "$aflag" ]; then
    printf "Option -a specified\n"
fi
if [ ! -z "$bflag" ]; then
    printf 'Option -b "%s" specified\n' "$bval"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: %s\n" "$*"
andcoz
źródło
2

Niedawno napisałem skrypt do pracy, który był wszechstronny i pozwalał na wiele rodzajów przełączników w dowolnej kolejności. Nie mogę ujawnić pełnego skryptu z oczywistych względów prawnych (nie wspominając o tym, że w tej chwili nie mam go przy sobie), ale oto jego sedno .. możesz umieścić go w podprogramie i nazwać na końcu twojego skryptu:

options () {

    if [ -n "$1" ]; then # test if any arguments passed - $1 will always exist
        while (( "$#" )); do  # process ALL arguments
            if [ "$1" = ^-t$ ]; then # -t short for "test"
                # do something here THEN shift the argument
                # shift removes it from $@ and reduces $# by
                # one if you supply no argument
                shift

            # we can also process multiple arguments at once
            elif [[ "$1" =~ ^--test=[:alnum:]{1,8}$ ]] && [[ "$2" =~ ^-t2$ ]] && [[ -n "$3" ]]; then # check for 3 arguments
                # do something more then remove them ALL from the arg list    
                shift 3
            else
                echo "No matching arguments!"
                echo "Usage: [script options list here]"
            fi
        done
    else
        echo "Usage: [script options list here]"
        exit 0
    fi
}

options "$@" # run options and loop through/process ALL arguments

Polecam ograniczenie skryptu bash do mniej niż 400 linii / 15k znaków; mój wyżej wspomniany skrypt przekroczył ten rozmiar i stał się bardzo trudny do pracy. Zacząłem przepisywać go w Perlu, który jest znacznie bardziej odpowiedni do tego zadania. Pamiętaj o tym podczas pracy nad skryptami w bash. Bash jest świetny dla małych skryptów i onelinerów, ale cokolwiek bardziej złożonego i lepiej pisać w Perlu.

Uwaga: nie testowałem powyższego, więc prawdopodobnie to nie działa, ale wyprowadzasz z tego ogólny pomysł.

laebshade
źródło
Sposób, w jaki dzwonisz optionsna końcu, jest nieprawidłowy, wróci -bash: syntax error near unexpected token $@. Nazwij to jak options "$@".
Chris Down,
Tak, pomieszałem Perla i Basha. Poprawione
laebshade
Ten whilewarunek nie powinien być (($#))zamiast tego?
manatwork
Dlaczego potrzebujesz dwóch zestawów nawiasów $#? Edycja: masz rację. Naprawiono towhile (( "$#" ))
laebshade