In dem Buch, das ich gerade lese – Learning the Bash Shell von O'Reilly – wird der Code wie folgt spezifiziert:
if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then
howmany=$1
shift
....
....
etc
Dabei wird das
grep
Suchdienstprogramm verwendet, um zu testen, ob$1
es mit dem entsprechenden Muster übereinstimmt. Dazu stellen wir^-[0-9][0-9]*$
grep den regulären Ausdruck zur Verfügung, der als „ein anfänglicher Bindestrich gefolgt von einer Ziffer, optional gefolgt von einer oder mehreren Ziffern“ interpretiert wird. Wenn eine Übereinstimmung gefunden wird,grep
wird die Übereinstimmung zurückgegeben und der Test ist wahr, andernfallsgrep
wird nichts zurückgegeben und die Verarbeitung wird mit dem Test fortgesetztelif
.Beachten Sie, dass wir den regulären Ausdruck in einfache Anführungszeichen eingeschlossen haben, um zu verhindern, dass die Shell das $ und * interpretiert, und um sie unverändert an grep weiterzuleiten.
Warum verliert der reguläre Ausdruck dann nicht '^-[0-9]'
seine Bedeutung wie in einfachen Anführungszeichen? Normalerweise verliert alles innerhalb einfacher Anführungszeichen seine Bedeutung.
Ich danke Ihnen für Ihre Hilfe.
Antwort1
Andere haben Ihre spezifische Frage bereits beantwortet, aber ich möchte hinzufügen,
if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then
Ist aus mehreren Gründen eine falsche Methode zum Überprüfen, ob eine Zeichenfolge mit einem regulären Ausdruck übereinstimmt:
- Sie können nicht
echo
für beliebige Daten verwenden - Das Lassen einer Parametererweiterung ohne Anführungszeichen wie
$1
oben entspricht dem Split+Glob-Operator. grep
gleicht den regulären Ausdruck nicht mit der gesamten Eingabe ab, sondern mit jeder Zeile der Eingabe. Daher würde esfoo\n-0\nbar
beispielsweise true zurückgeben.- Ein regulärer Ausdruck kann mit der Länge Null übereinstimmen, daher ist es im Allgemeinen falsch, zu prüfen, ob
grep
eine Ausgabe erzeugt (beachten Sie, dass die Befehlsersetzung nachfolgende Zeilenumbruchzeichen entfernt). Es ist besser,grep -q
den Beendigungsstatus von zu verwenden und sich darauf zu verlassengrep
, anstatt auf den von[
, und außerdem die Befehlsersetzung zu vermeiden. - Beachten Sie, dass dieser
grep
Befehl vereinfacht werden kann zugrep -xE '-[0-9]+'
bash
und haben einen eigenen Operator für (erweiterte) Regexp ksh93
- zsh
Matching. Um es portabel und zuverlässig in allen drei (und Bash-3.1) zu verwenden, lautet die Syntax:
re='^-[0-9]+$'
if [[ $1 =~ $re ]]; then
echo matches
fi
yash
und zsh
unterstützen Sie auch:
if [ "$1" '=~' '^-[0-9]+$' ]; then
echo matches
fi
Der Standardbefehl zum Durchführen von (grundlegenden) Regex-Abgleich von Zeichenfolgen lautet expr
:
if expr " $1" : ' -[0-9]\{1,\}$' > /dev/null; then
echo matches
fi
Beachten Sie, dass ^
(aber nicht $
) implizit in ist expr
. Wir verwenden dieses führende Leerzeichen auch, um Probleme mit Werten von zu vermeiden, $1
die Operatoren sind expr
.
Beachten Sie auch, dass, wenn der reguläre Ausdruck enthält \(...\)
, dies das Verhalten von beeinflusst expr
.
Alles in allem ist es besser, awk
stattdessen Folgendes zu verwenden, was eine weitere standardmäßige/portable Möglichkeit ist (beachten Sie, dass awk
erweiterte reguläre Ausdrücke verwendet werden):
if STRING=$1 RE='^-[0-9]+$' awk '
BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'; then
...
Oder verwenden Sie eine Funktion:
re_match() {
STRING=$1 RE=$2 awk '
BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'
}
if re_match "$1" '^-[0-9]+$'
In diesem Fall können Sie es auch mit einem Standardkonstrukt erreichen case
:
case $1 in
("" | *[!0-9-]* | [!-]* | - | ?*-*) ;;
(*) echo match;;
esac
Um zu verwenden grep
, können Sie es mit der --null
Option verwenden (sofern unterstützt, da dies keine Standardoption ist), um es anzuweisen, mit durch NULs getrennten Datensätzen statt mit durch Zeilenumbrüche getrennten Datensätzen zu arbeiten. Da in den meisten Shells $1
keine NULs enthalten können, sollte dies sicher sein:
if printf %s "$1" | grep --null -xq '-[0-9]+$'; then
echo match
fi
Antwort2
Einfache Anführungszeichen weisen die Shell an, die Umschließungszeichen so zu belassen, wie sie sind.ohne jede Interpretation. Der in Anführungszeichen gesetzte String wird unverändert an übergeben grep
, ohne Anführungszeichen: Bei grep
der Suche nach den Argumenten wird Folgendes angezeigt:
grep
Und
^-[0-9][0-9]*$
und handelt danach. (Lesen SieSo werden Programme ausgeführtwenn Sie neugierig auf die Argumentkonstruktion in Linux sind.)
bash
und grep
sind unterschiedlich. Die Art und Weise, wie dieser Befehl Anführungszeichen verwendet, stellt sicher, dass bash
die Zeichenfolge nicht verarbeitet wird, sondern grep
dies tut.
Antwort3
Einfache Anführungszeichen verhindernGlotzen( bash
Platzhalter wie interpretieren lassen *
) und Variablenerweiterung durch die Verwendung von $
. Im Grunde sagen Sie, bash
„nehmen Sie diese Zeichen wörtlich und übergeben Sie sie an grep
“. Wenn grep
sie angezeigt werden, ist es so aufgebaut, dass es reguläre Ausdrücke versteht, alsoDannDer reguläre Ausdruck wird darin interpretiert grep
.
Kürzere Version: Durch das Setzen einfacher Anführungszeichen für Argumente können Sie der Verarbeitung durch Ihre Shell entgehen, bevor das Argument an den Befehl übergeben wird.
Antwort4
Es verliert seine Bedeutung. grep
verwendet fast dieselben Regex-Muster wie Bash.