Controlla se uno dei parametri di uno script bash corrisponde a una stringa


67

Sto cercando di scrivere uno script in cui desidero verificare se uno qualsiasi dei parametri passati a uno script bash corrisponde a una stringa. Il modo in cui l'ho installato in questo momento è

if [ "$3" != "-disCopperBld" -a "$4" != "-disCopperBld" -a "$5" != "-disCopperBld" -a "$6" != "-disCopperBld"]

ma potrebbe esserci un gran numero di parametri, quindi mi chiedevo se c'è un modo migliore per farlo?

Grazie

EDIT: ho provato questo pezzo di codice e ho chiamato lo script con l'opzione -disableVenusBld, ma stampa comunque "Avvio della build". Sto facendo qualcosa di sbagliato? Grazie in anticipo!

while [ $# -ne 0 ]
do
    arg="$1"
    case "$arg" in
        -disableVenusBld)
            disableVenusBld=true
            ;;
        -disableCopperBld)
            disableCopperBld=true
            ;;
        -disableTest)
            disableTest=true
            ;;
        -disableUpdate)
            disableUpdate=true
            ;;
        *)
            nothing="true"
            ;;
    esac
    shift
done

if [ "$disableVenusBld" != true ]; then
    echo "Starting build"
fi

Grazie per le risposte ragazzi, apprezzo che vi prendiate del tempo per aiutarmi. Ho provato un pezzo di codice, ma non riesco a capire cosa non va. Qualche idea? (Ho incollato il codice in una modifica del mio post originale)
iman453

Hmm: funziona per me. Ho aggiunto #! /bin/sh -all'inizio di ciò che hai incluso lì, reso eseguibile lo script, quindi ./t.shstampa "Avvio build", ma ./t.sh -disableVenusBldnon stampa nulla.
Norman Gray,

Risposte:


59

Sembra che tu stia facendo la gestione delle opzioni in uno script di shell. Ecco il linguaggio per questo:

#! /bin/sh -

# idiomatic parameter and option handling in sh
while test $# -gt 0
do
    case "$1" in
        --opt1) echo "option 1"
            ;;
        --opt2) echo "option 2"
            ;;
        --*) echo "bad option $1"
            ;;
        *) echo "argument $1"
            ;;
    esac
    shift
done

exit 0

(Esistono un paio di convenzioni per il rientro di ;;, e alcune shell consentono di fornire le opzioni come (--opt1), per aiutare con la corrispondenza del controvento, ma questa è l'idea di base)


3
Una shiftdichiarazione viene utilizzato quando il numero di argomenti per un comando non è noto in anticipo, ad esempio quando gli utenti possono dare il maggior numero di argomenti come gli pare. In tali casi, gli argomenti vengono elaborati in un whileciclo con una condizione di test di $#. Questa condizione è vera purché il numero di argomenti sia maggiore di zero. La $1variabile e l' shiftistruzione elaborano ogni argomento. Il numero di argomenti viene ridotto ogni volta che shiftviene eseguito e alla fine diventa zero, su cui whileesce il ciclo. fonte
Serge Stroobandt,


26

Questo ha funzionato per me. Fa esattamente quello che hai chiesto e niente di più (nessuna elaborazione delle opzioni). Che sia positivo o negativo è un esercizio per il poster :)

if [[ "$*" == *YOURSTRING* ]]
then
    echo "YES"
else
    echo "NO"
fi

Questo sfrutta la gestione speciale delle staffe $* super-test [[... e bash ]].


2
IMHO questa doveva essere la risposta più corretta, poiché la domanda richiede solo di verificare la presenza di un parametro. Ho modificato, tuttavia, cambiando $*in $@, poiché la stringa da testare potrebbe contenere spazi e aggiungere un collegamento alla documentazione di Bash al riguardo.
h7r

9
Intendevi usare l'operatore = ~? Altrimenti non vedo perché questo dovrebbe funzionare, e in effetti non funziona quando provo lo script esatto.
Seppo Enarvi,

3
Non funziona. bash -c 'echo args=$*; [[ "$@" == "bar" ]] && echo YES || echo NO' -- foo bar
Tobia,

2
Questo confronta l'intero elenco di argomenti con your string. Penso che tu debba fare ciò che è suggerito da questa risposta . cioè: bash -c 'echo args=$*; for i in "$@" ; do [[ $i == "bar" ]] && echo "Is set!" && break ; done' -- bar foofunzionerebbe.
Starfry,

2
Questa risposta è stata sbagliata negli ultimi quattro anni perché la modifica di h7r l'ha interrotta. La risposta originale (che ora ho ripristinato) funziona, a condizione che "la tua stringa" non contenga caratteri glob e con alcuni falsi positivi. Ad esempio, se il comando è create a new certificatee "la tua stringa" è cat, questo segnalerà una corrispondenza perché certificate contiene cat .
Scott,

8

Che ne dici di cercare (con caratteri jolly) l'intero spazio dei parametri:

if [[ $@ == *'-disableVenusBld'* ]]
then

Modifica: Ok, ok, quindi quella non era una risposta popolare. Che ne dici di questo, è perfetto !:

if [[ "${@#-disableVenusBld}" = "$@" ]]
then
    echo "Did not find disableVenusBld"
else
    echo "Found disableVenusBld"
fi

Edit2: Ok, ok, forse questo non è perfetto ... Pensa che funzioni solo se -param è all'inizio dell'elenco e corrisponderà anche a -paramXZY o -paramABC. Penso ancora che il problema originale possa essere risolto molto bene con la manipolazione delle stringhe di bash, ma non l'ho ancora risolto qui ... -Puoi ??


Il tuo secondo suggerimento - confrontare la sostituzione del filtro con la sostituzione completa - funziona abbastanza bene e ha il vantaggio di non interrompere l'elenco degli argomenti.
Donal Fellows,

Potresti spiegare cosa fa (in particolare ${@#) il secondo suggerimento ?
velop

1
@velop Sure! Quindi sai che $@è una variabile speciale che contiene tutti gli argomenti della riga di comando? Beh, ho appena usato la manipolazione di stringhe di Bash su quella variabile per rimuovere la sottostringa "-disableVenusBld", e poi l'ho confrontata con l'originale $@. Quindi, se $@uguale a -foo -barallora ${@#-disableVenusBld}sarebbe ancora -foo -bar, quindi posso vedere che la bandiera che sto cercando non è presente. Tuttavia, se $@uguale sarebbe -foo -disableVenusBld -barallora che non è uguale , quindi mi dice che la bandiera che sto cercando è presente! Bene eh! ${@#-disableVenusBld}-foo -bar$@
Ricco

@velop Ulteriori informazioni sulla manipolazione delle stringhe di Bash qui: tldp.org/LDP/abs/html/string-manipulation.html
Rich

@Rich piuttosto pulito ^^, grazie per la spiegazione.
velop,

4
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

Se è necessario testare solo i parametri a partire da $3, eseguire la ricerca in una funzione:

## Usage: search_trailing_parameters NEEDLE NUM "$@"
## Search NEEDLE amongst the parameters, skipping $1 through ${$NUM}.
search_trailing_parameters () {
  needle=$1
  shift $(($2 + 2))
  for x; do
    if [ "$x" = "$needle" ]; then return 0; fi
  done
  return 1
}
if search_trailing_parameters -disCopperBld 2 "$@"; then
  ...
fi

Ma mi chiedo perché stai provando a farlo in primo luogo, non è un'esigenza comune. Di solito, elabori le opzioni in ordine, come nella risposta di Dennis alla tua domanda precedente .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.