Überprüfen Sie, ob einer der Parameter eines Bash-Skripts mit einer Zeichenfolge übereinstimmt

65

Ich versuche, ein Skript zu schreiben, in dem überprüft werden soll, ob einer der an ein Bash-Skript übergebenen Parameter mit einer Zeichenfolge übereinstimmt. Die Art, wie ich es gerade eingerichtet habe, ist

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

aber es könnte eine große Anzahl von Parametern geben, also habe ich mich gefragt, ob es einen besseren Weg gibt, dies zu tun?

Vielen Dank

BEARBEITEN: Ich habe diesen Code ausprobiert und das Skript mit der Option -disableVenusBld aufgerufen, aber es wird immer noch "Starting build" ausgegeben. Mache ich etwas falsch? Danke im Voraus!

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
iman453
quelle
Vielen Dank für die Antworten, ich weiß es zu schätzen, dass du dir Zeit nimmst, mir zu helfen. Ich habe einen Teil des Codes ausprobiert, aber ich kann nicht herausfinden, was falsch läuft. Irgendwelche Ideen? (Ich habe den Code in eine Bearbeitung meines ursprünglichen Beitrags
eingefügt
Hmm: es funktioniert bei mir. Ich habe oben hinzugefügt #! /bin/sh -, was Sie dort eingefügt haben, das Skript ausführbar gemacht und dann ./t.sh"Starting build" ./t.sh -disableVenusBldausgegeben , aber nichts gedruckt.
Norman Gray

Antworten:

57

Es sieht so aus, als würden Sie Optionen in einem Shell-Skript verarbeiten. Hier ist die Redewendung dafür:

#! /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

(Es gibt ein paar Konventionen zum Einrücken der ;;, und einige Shells erlauben es Ihnen, die Optionen als anzugeben , um beim Anpassen der (--opt1)Klammern zu helfen, aber dies ist die Grundidee.)

Norman Gray
quelle
3
Eine shiftAnweisung wird verwendet, wenn die Anzahl der Argumente für einen Befehl nicht im Voraus bekannt ist, z. B. wenn Benutzer beliebig viele Argumente angeben können. In solchen Fällen werden die Argumente in einer whileSchleife mit einer Testbedingung von verarbeitet $#. Diese Bedingung ist erfüllt, solange die Anzahl der Argumente größer als Null ist. Die $1Variable und die shiftAnweisung verarbeiten jedes Argument. Die Anzahl der Argumente wird bei jeder shiftAusführung verringert und wird schließlich zu Null, worauf die whileSchleife beendet wird. Quelle
Serge Stroobandt
Hier ist ein ähnliches Beispiel mit zusätzlicher echo $1 | sedArgumentwertverarbeitung .
Serge Stroobandt
26

Das hat bei mir funktioniert. Es macht genau das, was Sie gefragt haben und nichts mehr (keine Optionsverarbeitung). Ob das gut oder schlecht ist, ist eine Übung für das Plakat :)

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

Dies nutzt eine spezielle Handhabung von $* und bash super-Test [[... ]]Klammern.

Reiche Homolka
quelle
2
IMHO musste dies die richtigste Antwort sein, da die Frage nur das Vorhandensein eines Parameters zu überprüfen erfordert. Ich habe jedoch geändert, $*um $@, da die zu testende Zeichenfolge Leerzeichen haben könnte und Link zu bashs Dokumentation darüber hinzugefügt.
07.02.15 Uhr,
9
Wollten Sie den Operator = ~ verwenden? Ansonsten verstehe ich nicht, warum dies funktionieren sollte, und es funktioniert auch nicht, wenn ich das genaue Skript ausprobiere.
Seppo Enarvi
3
Funktioniert nicht. bash -c 'echo args=$*; [[ "$@" == "bar" ]] && echo YES || echo NO' -- foo bar
Tobia
2
Dies vergleicht die gesamte Argumentliste mit your string. Ich denke, Sie müssen das tun, was in dieser Antwort vorgeschlagen wird . dh: bash -c 'echo args=$*; for i in "$@" ; do [[ $i == "bar" ]] && echo "Is set!" && break ; done' -- bar foowürde funktionieren.
Starfry
1
Diese Antwort war in den letzten vier Jahren falsch, weil die Bearbeitung von h7r sie gebrochen hat. Die ursprüngliche Antwort (die ich jetzt wiederhergestellt habe) funktioniert, vorausgesetzt, dass "Ihre Zeichenfolge" keine Glob-Zeichen enthält und einige falsch positive Ergebnisse enthält. Wenn der Befehl beispielsweise lautet create a new certificateund "Ihre Zeichenfolge" lautet cat, wird eine Übereinstimmung gemeldet, da certificate enthält cat .
Scott,
8

Wie wäre es mit der Suche (mit Platzhaltern) des gesamten Parameterraums:

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

Edit: Ok, ok, das war also keine beliebte Antwort. Wie wäre es mit diesem, es ist perfekt !:

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

Edit2: Ok, ok, vielleicht ist das nicht perfekt ... Ich denke, es funktioniert nur, wenn -param am Anfang der Liste steht und auch -paramXZY oder -paramABC entspricht. Ich denke immer noch, dass das ursprüngliche Problem sehr gut mit Bash-String-Manipulation gelöst werden kann, aber ich habe es hier nicht ganz geknackt ... -Kannst du?

Reich
quelle
Ihr zweiter Vorschlag - der Vergleich der Filterersetzung mit der vollständigen Ersetzung - funktioniert recht gut und hat den Vorteil, dass die Liste der Argumente nicht gestört wird.
Donal Fellows
Könnten Sie erklären, was der zweite Vorschlag (besonders ${@#) tut?
14.
1
@velop Sicher! Sie wissen also, dass dies $@eine spezielle Variable ist, die alle Befehlszeilenargumente enthält? Nun, ich habe gerade die Bash-String-Manipulation für diese Variable verwendet, um den Teilstring "-disableVenusBld" zu entfernen, und dann vergleiche ich ihn mit dem Original $@. Also , wenn $@gleich -foo -bardann ${@#-disableVenusBld}noch sein würde -foo -bar, damit ich sehen kann , dass die Flagge , die ich suche nicht vorhanden ist. Wenn es jedoch $@gleich -foo -disableVenusBld -bardann ${@#-disableVenusBld}wäre -foo -bardas nicht gleich $@, so sagt mir, dass das Flag Ich suche vorhanden ist! Cool wie!
Rich
@velop Weitere Informationen zur Manipulation von Bash-Strings finden Sie hier: tldp.org/LDP/abs/html/string-manipulation.html
Rich
@Rich ziemlich ordentlich ^^, danke für die Erklärung.
Velop
3
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

Wenn Sie nur die Parameter testen müssen, die bei beginnen $3, führen Sie die Suche in einer Funktion durch:

## 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

Aber ich frage mich, warum Sie das überhaupt versuchen, es ist keine alltägliche Notwendigkeit. Normalerweise bearbeiten Sie die Optionen in der Reihenfolge, wie in Dennis 'Antwort auf Ihre vorherige Frage .

Gilles
quelle