2013-05-20 3 views
31

mi piacerebbe utilizzare getopts all'interno di una funzione che ho definito nel mio .bash_profile. L'idea è che vorrei passare alcuni flag a questa funzione per alterarne il comportamento.Utilizzando getopts all'interno di una funzione di Bash

Ecco il codice:

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

Quando invoco così:

t -a bc 

ottengo questo output:

-a bc 
? 
  

Cosa c'è di sbagliato? Mi piacerebbe ottenere il valore bc senza spostare e analizzare manualmente. Come utilizzare correttamente getopts all'interno di una funzione?

EDIT: corretto il mio frammento di codice per provare $ OPTARG, senza alcun risultato

EDIT # 2: OK scopre il codice va bene, il mio guscio è stato in qualche modo incasinato. Aprire una nuova finestra l'ha risolto. Il valore di arg era in effetti in $ OPTARG.

risposta

64

Come @Ansgar sottolinea, l'argomento per l'opzione viene memorizzato in ${OPTARG}, ma questo non è l'unica cosa a cui prestare attenzione quando si utilizza getopts all'interno di una funzione. È inoltre necessario assicurarsi che ${OPTIND} è locale alla funzione da una disinserimento o dichiarandola local, altrimenti si riscontrare un comportamento imprevisto quando si richiama la funzione più volte.

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 

Esempio gestito:

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

Se commento fuori # local OPTIND, questo è quello che si ottiene, invece:

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

Oltre a questo, il suo utilizzo è la stessa di quando utilizzato all'esterno di una funzione.

+7

Avrei votato questa risposta un centinaio di volte se potessi. Questo mi stava facendo impazzire !! –

+0

1.) Il '1' in' 1> & 2' non è necessario. 2.) Ti sei perso per definire 'a',' o' e 'OPTARG' come locali. 3.) Il 'exit' non uscirà dallo script ma solo una sotto-shell. Per uscire dallo script è necessario 'set -e' nella shell esterna e' exit 1' nella sub-shell. L'esempio non innesca il problema, ma un 'MSG = $ (pippo ...)' lo farà. – ceving

+0

@ceving 1) Si tratta di uno stile di codifica ma, no, non è necessario secondo la definizione della lingua. 2) Concordato, quelli dovrebbero essere locali. 3) Come hai detto, l'uscita * * uscirà dallo script nel mio esempio. Ovviamente 'exit' non uscirà da sub shell ma questo non è un problema specifico a questa domanda. Non devi usare 'set -e', devi solo assicurarti di prendere l'errore e' MSG = $ (foo ...) || die' funziona altrettanto bene. 'set -e' è una soluzione al problema [ma non è a prova di idiota] (http://mywiki.wooledge.org/BashFAQ/105) e io, come molti altri, non consiglio di usarlo. –

4

L'argomento è archiviato nella varable $OPTARG.

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

uscita:

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

Mi dispiace in modo non corretto incollato il mio frammento di codice ... Ho anche echo $ OPTARG, questa è la terza linea che è vuota. Altre idee? – Magnus

+0

@Magnus Probabilmente perché hai chiamato la funzione più volte e '$ OPTIND' non è definito localmente (vedi la risposta di Adrian). Mentre sono grato che tu abbia accettato la mia risposta, probabilmente dovresti accettare piuttosto il suo. –

+0

Il codice funziona solo quando si incolla nella shell, ma non nello script. – kenorb

8

Ecco semplice esempio di getopts utilizzo all'interno funzione shell:

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

uscita:

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

Come @Adrian pointed out, local OPTIND (o OPTIND=1) deve essere stabilito come shell non reimposta OPTIND automaticamente tra multiple calls to getopts (man bash).

La base-sintassi per getopts è:

getopts OPTSTRING VARNAME [ARGS...] 

e per impostazione predefinita, senza specificare argomenti equivale a chiamare in modo esplicito con "$ @" che è: getopts "a:" opts "[email protected]".

In caso di problemi, queste sono le variabili utilizzate per getopts da verificare:

  • OPTIND - l'indice del prossimo argomento da trattare,
  • OPTARG - variabile è impostata su qualsiasi argomento per un opzione trovata da getopts,
  • OPTERR (non POSIX) - impostare su 0 o 1 per indicare se Bash deve visualizzare i messaggi di errore generati dallo getopts.

ulteriormente più, vedi: alla festa hacker Wiki

+0

Risposta molto ponderata. Non so se funziona, ma ottimo lavoro. – Drew