Używanie getopts wewnątrz funkcji Bash

Chciałbym użyć getopts wewnątrz funkcji, którą zdefiniowałem w moim .bash_profile. Chodzi o to, że chciałbym przekazać kilka flag do tej funkcji, aby zmienić jej zachowanie.

Oto kod:

function t() {
    echo $*
    getopts "a:" OPTION
    echo $OPTION
    echo $OPTARG
}

Kiedy wywołuję to tak:

t -a bc

I get this output:

-a bc
?
 
Co się stało? Chciałbym uzyskać wartość bc bez ręcznego przesuwania i parsowania. Jak poprawnie używać getopts wewnątrz funkcji?

EDIT: poprawiłem mój fragment kodu, aby spróbować $OPTARG, aby no avail

EDIT # 2: OK okazuje się, że kod jest w porządku, moja powłoka była jakoś popsuta. Otwarcie nowego okna rozwiązało problem. Wartość arg rzeczywiście była w $OPTARG.

Author: Adrian Frühwirth, 2013-05-20

3 answers

Jak wskazuje @Ansgar, argument do opcji jest przechowywany w ${OPTARG}, ale nie jest to jedyna rzecz, na którą należy uważać podczas używania getopts wewnątrz funkcji. Musisz również upewnić się, że ${OPTIND} jest lokalna dla funkcji, wyłączając ją lub deklarując ją local, w przeciwnym razie napotkasz nieoczekiwane zachowanie podczas wielokrotnego wywoływania funkcji.

t.sh:

#!/bin/bash

foo()
{
    foo_usage() { echo "foo: [-a <arg>]" 1>&2; exit; }

    local OPTIND o a
    while getopts ":a:" o; do
        case "${o}" in
            a)
                a="${OPTARG}"
                ;;
            *)
                foo_usage
                ;;
        esac
    done
    shift $((OPTIND-1))

    echo "a: [${a}], non-option arguments: $*"
}

foo
foo -a bc bar quux
foo -x

Przykładowe uruchomienie:

$ ./t.sh
a: [], non-option arguments:
a: [bc], non-option arguments: bar quux
foo: [-a <arg>]

Jeśli skomentujesz # local OPTIND, to dostaniesz zamiast:

$ ./t.sh
a: [], non-option arguments:
a: [bc], non-option arguments: bar quux
a: [bc], non-option arguments:

Poza tym, jego użycie jest takie samo jak w przypadku użycia poza funkcją.

 75
Author: Adrian Frühwirth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-13 07:01:09

Oto prosty przykład getopts użycie w funkcji powłoki:

#!/usr/bin/env bash
t() {
  local OPTIND
  getopts "a:" OPTION
  echo Input: $*, OPTION: $OPTION, OPTARG: $OPTARG
}
t "$@"
t -a foo

Wyjście:

$ ./test.sh -a bc
Input: -a bc, OPTION: a, OPTARG: bc
Input: -a foo, OPTION: a, OPTARG: foo

Jako @ Adrian wskazał, local OPTIND (or OPTIND=1) musi być ustawione, ponieważ shell nie resetuje OPTIND automatycznie pomiędzy wieloma wywołaniami do getopts (man bash).

Składnia bazowa dla getopts to:

getopts OPTSTRING VARNAME [ARGS...]

I domyślnie niepodanie argumentów jest równoznaczne z jawnym wywołaniem go za pomocą"$@", czyli: getopts "a:" opts "$@".

W przypadku problemy, są to zmienne używane do sprawdzania getopts:

  • OPTIND - indeks do następnego argumentu do przetworzenia,
  • OPTARG - zmienna jest ustawiana na dowolny argument dla opcji znalezionej przez getopts,
  • OPTERR (nie POSIX) - Ustaw na 0 LUB 1, aby wskazać, czy Bash powinien wyświetlać komunikaty o błędach generowane przez getopts.

Więcej więcej, Zobacz: mały tutorial getopts na Wiki hakerów Bash

 9
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:36

Argument jest przechowywany w zmiennej $OPTARG.

function t() {
  echo $*
  getopts "a:" OPTION
  echo $OPTION
  echo $OPTARG
}

Wyjście:

$ t -a bc
-a bc
a
bc
 4
Author: Ansgar Wiechers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-20 17:23:04