Ich möchte eine Funktion schreiben, die prüft, ob eine gegebene Variable, sagen wir var
, mit einem der Wörter in einer gegebenen Liste von Zeichenfolgen beginnt. Diese Liste ändert sich nicht.
Zur Instanziierung tun wir so, als ob ich prüfen möchte, ob mit oder var
beginnt .aa
abc
3@3
Außerdem möchte ich prüfen, ob var
das Zeichen enthalten ist >
.
Nehmen wir an, diese Funktion wird aufgerufen check_func
. Meine beabsichtigte Verwendung sieht ungefähr so aus:
if check_func "$var"; then
do stuff
fi
Beispielsweise sollte es für
aardvark
, abcdef
, [email protected]
und „Dinge erledigen“ 12>5
.
Ich habe gesehendiese SO-Fragewenn ein Benutzer einen Teil der Arbeit bereitstellt:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
Meine Idee ist, dass ich die oben genannte Liste durchlaufe und diese Funktion verwende. Meine Schwierigkeit besteht darin, dass ich nicht genau verstehe, wie das Beenden (oder was auch immer das Zurückkehren ersetzt) erfolgen soll, damit dies funktioniert.
Antwort1
check_prefixes () {
value=$1
for prefix in aa abc 3@3; do
case $value in
"$prefix"*) return 0
esac
done
return 1
}
check_contains_gt () {
value=$1
case $value in
*">"*) return 0
esac
return 1
}
var='aa>'
if check_prefixes "$var" && check_contains_gt "$var"; then
printf '"%s" contains ">" and starts with one of the prefixes\n' "$var"
fi
Ich habe die Tests auf zwei Funktionen aufgeteilt. Beide verwenden case ... esac
und geben Erfolg (Null) zurück, sobald dieser festgestellt werden kann. Wenn nichts übereinstimmt, wird Fehler (1) zurückgegeben.
Um die Liste der Präfixe dynamischer zu gestalten, könnte man die erste Funktion auch so schreiben:
check_prefixes () {
value=$1
shift
for prefix do
case $value in
"$prefix"*) return 0
esac
done
return 1
}
(der zu prüfende Wert ist das erste Argument, das wir in der Argumentenliste der Funktion speichern value
und dann wieder entfernen; dann iterieren wir über die restlichen Argumente) und rufen es dann auf alsshift
check_prefixes "$var" aa abc 3@3
Die zweite Funktion könnte auf ähnliche Weise geändert werden in
check_contains () {
value=$1
shift
case $value in
*"$1"*) return 0
esac
return 1
}
(um nach einer beliebigen Teilzeichenfolge zu suchen) oder
check_contains_oneof () {
value=$1
shift
for substring do
case $value in
*"$substring"*) return 0
esac
done
return 1
}
(um nach einer beliebigen Anzahl von Teilzeichenfolgen zu suchen)
Antwort2
Für Bash:
Mithilfe der Eigenschaften von regulären Ausdrücken können Sie start
mit ^
und contain
durch nichts schreiben.
Die Liste der zu prüfenden regulären AusdrückeStartmit aa
abc
oder 3@3
undenthält >
Ist:
^aa ^abc ^3@3 >
Machen Sie daraus einrichtigListe in Anführungszeichen setzen und Bash auffordern, reguläre Ausdrücke zu verwenden ( =~
):
check_func() {
matched=1
for test_regex in '^aa' '^abc' '^3@3' '>'; do
if [[ $var =~ $test_regex ]] ; then
matched=0
break
fi
done
return "$matched"
}
var='aaIsAMatch'
if check_func; then
echo "A match was found"
fi
Die Funktion hat die Liste der Übereinstimmungen und den Namen der Variable fest codiert.
Angeben der Liste der regulären Ausdrücke in einer Array-Variablen und des zu testenden Werts für das erste Argument:
check_func() {
local matched; matched=1
for t in "${test_regex[@]}"; do
[[ $1 =~ $t ]] && { matched=0; break; }
done
return "$matched"
}
test_regex=('^aa' '^abc' '^3@3' '>')
if check_func 'aaIsAMatch'; then
echo "A match was found"
fi
Die Funktion könnte weiter verbessert werden, um den Namen einer Variablen (anstelle eines Werts) als erstes Argument zu verwenden.
Posix-Datenbank
Da es in POSIX-Shells keine regulären Ausdrücke gibt und die einzige Möglichkeit zum Testen eine Case-Anweisung ist, müssen wir eine Case-Anweisung verwenden. Leider müssen wir bei älteren Shells ([keine erweiterten Globs verfügbar][1]) eine Schleife ausführen, um alle Tests durchzuführen. Und die Globs müssen sein:
'aa*' 'abc*' '3@3*' '*>*'
Ein Skriptbeispiel, das mehrere Eingabezeichenfolgen anhand mehrerer Globs testet:
check_func() { :
matched=1
value=$1; shift
for t in "$@"; do
case $value in $t) matched=0; #break;; esac
echo "matched $value with $t"
;;
esac
done
return "$matched"
}
for var in abdg wabcde aadef abcde 3@3hello hmm3@3hell 'we>we' 'a>dfff' 'dfd>' 'a> de' 'a*> fg'; do
if check_func "$var" 'aa*' 'abc*' '3@3*' '*>*'; then
echo "========A match was found for \"$var\""
fi
done
Eine einfachere Version der Funktion, die genau Ihrer Anfrage entspricht:
check_func() { :
matched=1
value=$1; shift
for t in "$@"; do
case $value in $t) matched=0; break;; esac
done
return "$matched"
}
Antwort3
Die Anweisung bewirkt Folgendes case
: Sie übernimmt den zweiten Parameter der Funktion ( $2
). Wenn dieser mit dem Muster übereinstimmt "$1"*
, also dem ersten Argument der Funktion, gefolgt von irgendetwas, wird true
die Anweisung ausgeführt und beendet case
. true
Dies geschieht nichts und gibt den Status 0 zurück. Andernfalls, wenn es übereinstimmt *
, also mit irgendetwas, wird false
die case
Anweisung ausgeführt und beendet. Dies false
geschieht nichts und gibt den Status 1 zurück. Somit hat die case
Anweisung den Status 0, wenn der zweite Parameter mit dem ersten Parameter beginnt, und andernfalls 1. Da dies die letzte (und einzige) Anweisung in der Funktion ist, gibt die Funktion 0 zurück, wenn der zweite Parameter mit dem ersten Parameter beginnt, und andernfalls 1.
Bedingte Anweisungen wie if
in der Shell betrachten eine Anweisung als wahr, wenn sie 0 zurückgibt, und andernfalls als falsch. Wird daher if beginswith "$var" "string"; then echo yes; else echo no; fi
gedruckt yes
, wenn der Wert var
mit beginnt, string
und no
andernfalls.
Es gibt mehrere alternative Möglichkeiten, diese Funktion zu schreiben. Beispielsweise hätte der Autor return 0
oder return 1
anstelle von true
und verwenden können false
, da diese die letzte Anweisung in der Funktion sind. Die Art und Weise, wie die Funktion geschrieben wurde, ermöglicht es, ihren Hauptteil direkt zu verwenden, ohne ihn in eine Funktion einzuschließen, indem einfach die Verweise auf die Funktionsparameter ( $1
und $2
) in die Zeichenfolgen geändert werden, mit denen Sie arbeiten möchten.
Um mehrere Präfixe zuzulassen, durchlaufen Sie sie in einer Schleife. Sobald Sie ein passendes Präfix gefunden haben, kehren Sie mit dem Status „true“ (0) aus der Funktion zurück. Wenn keines der Präfixe übereinstimmt, geben Sie den Status „false“ (üblicherweise 1) zurück.
# begins_with STRING PREFIX1 PREFIX2...
# Test if STRING starts with any of PREFIX1, PREFIX2, ...
begins_with () {
string=$1
shift
for prefix in "$@"; do
case "$string" in
"$prefix"*) return 0;;
esac
done
return 1
}
if begins_with "$var" 'aa' 'abc' '3@3'; then
echo "The value starts with one of the permitted prefixes"
fi
Um auf ein Suffix zu testen, verwenden Sie das Muster *"$suffix"
anstelle von "$prefix"*
. Um auf eine Teilzeichenfolge zu testen, verwenden Sie *"$substring"*
. Beachten Sie, dass die Anführungszeichen hier erforderlich sind, da die Variable sonst als Muster interpretiert würde. Beispiel:
suffix='?'
case "$var" in
*"$suffix") echo "The value of var ends with a question mark";;
esac
case "$var" in
*$suffix) echo "The value of var is not empty";;
esac
Antwort4
Überarbeitet aufgrund der Klarstellung der Frage: Dies ist weniger elegant (und viel weniger flexibel), aber kompakter als die anderen Antworten.
check_func() {
case "$1" in
( aa* | abc* | 3@3* | *">"*)
return 0
esac
return 1
}
Dies gibt true für aardvark
, abcdef
, [email protected]
und zurück 12>5
. Und natürlich auch für aard>vark
, abc<def>ghi
und 3@3>3
.