2013-05-20 22 views
31

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

Oto kod:

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

Gdy przywołuję to tak:

t -a bc 

uzyskać ten wynik:

-a bc 
? 
  

Co się stało? Chciałbym uzyskać wartość bc bez ręcznego przesuwania i parsowania. Jak prawidłowo używać funkcji getopts w funkcji?

EDIT: poprawione mój fragment kodu, aby spróbować $ OPTARG, bezskutecznie

EDIT # 2: OK, okazuje się, że kod jest w porządku, moja skorupa została w jakiś sposób zawiedli. Otwarcie nowego okna rozwiązało to. Wartość arg była rzeczywiście w $ OPTARG.

Odpowiedz

64

Jak @Ansgar wskazuje argument do opcji są przechowywane w ${OPTARG}, ale to nie jest jedyną rzeczą, należy zwrócić uwagę podczas korzystania getopts wewnątrz funkcji. Musisz również upewnić się, że ${OPTIND} jest lokalną dla tej funkcji, albo je usuwając z pamięci, albo deklarując ją jako local, w przeciwnym razie napotkasz nieoczekiwane zachowanie podczas wielokrotnego wywoływania tej 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ład uruchomić:

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

Jeśli wykomentuj # local OPTIND, to co można dostać zamiast:

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

Poza tym, jej użycie jest taki sam jak w przypadku użycia poza funkcją.

+7

Chciałbym przegłosować tę odpowiedź sto razy, gdybym mógł. To doprowadzało mnie do szału !! –

+0

1.) '1' w' 1> i 2' nie jest konieczne. 2.) Brakowało ci zdefiniowania "a", "o" i "OPTARG" jako lokalnych. 3.) 'exit' nie wyjdzie ze skryptu, ale tylko pod-powłokę. Aby wyjść ze skryptu, konieczne jest ustawienie 'set -e' w powłoce zewnętrznej i 'exit 1' w pod-powłoce. Przykład nie uruchamia problemu, ale zrobi to 'MSG = $ (foo ...)'. – ceving

+0

@cending 1) Jest to kwestia stylu kodowania, ale nie, nie jest to konieczne zgodnie z definicją języka. 2) Uzgodnione, powinny być lokalne. 3) Jak powiedziałeś, wyjście * spowoduje * wyjście ze skryptu w moim przykładzie. Oczywiście 'exit' nie spowoduje wypuszczenia powłoki dodatkowej, ale nie jest to konkretny problem z tym pytaniem. Nie musisz używać 'set -e', musisz tylko upewnić się, że złapałeś błąd i' MSG = $ (foo ...) || die' działa równie dobrze. 'set -e' to jedno rozwiązanie problemu [ale nie jest to idiotoodporne] (http://mywiki.wooledge.org/BashFAQ/105), a ja, jak wielu innych, nie polecam korzystania z niego. –

4

Argument jest przechowywany w zmiennej $OPTARG.

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

wyjściowa:

$ t -a bc 
-a bc 
a 
bc
+0

Niestety ja błędnie wklejony fragment mojego kodu ... Ja też echo $ Optarg, że to 3. linia, która jest pusta. Jakieś inne pomysły? – Magnus

+0

@Magnus Prawdopodobnie dlatego, że wywołałeś tę funkcję kilka razy i '$ OPTIND' nie jest zdefiniowany lokalnie (patrz odpowiedź Adriana). Choć jestem wdzięczny, że przyjąłeś moją odpowiedź, powinieneś raczej raczej zaakceptować jego odpowiedź. –

+0

Kod działa tylko podczas wklejania do powłoki, ale nie w skrypcie. – kenorb

8

Oto prosty przykład getopts użytkowania w funkcję powłoki:

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

wyjściowa:

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

Jak @Adrian pointed out, local OPTIND (lub OPTIND=1) musi być ustawiony jako powłoka nie resetuje OPTIND automatycznie między multiple calls to getopts (man bash).

Podstawa składni dla getopts jest:

getopts OPTSTRING VARNAME [ARGS...] 

i domyślnie, nie podając argumentów jest równoznaczne z jawnie nazywając go „$ @”, która jest: getopts "a:" opts "[email protected]".

W przypadku problemów, są wykorzystywane zmienne dla getopts sprawdzić:

  • OPTIND - indeks do kolejnego argumentu do przetworzenia,
  • OPTARG - zmienna jest ustawiona na żadnym argumentem za opcja znaleziona przez getopts,
  • OPTERR (nie POSIX) - ustawiona na 0 lub 1, aby wskazać, czy Bash powinien wyświetlać komunikaty o błędach generowane przez getopts.

Co więcej, zobacz: w bash Hakerzy Wiki

+0

Bardzo starannie rozłożona odpowiedź. Nie wiem, czy to działa, ale świetna robota. – Drew