Regexe in Bashscripts

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
Quilmes
Beiträge: 87
Registriert: 11.04.2008 23:25:52

Regexe in Bashscripts

Beitrag von Quilmes » 11.01.2010 13:44:37

Hallo,
In einem Bashscript soll ein eingegebener String nur aus aphanumerischen Zeichen sowie "-_."bestehen. Beim Versuch das umzusetzen, bin ich über einige Ungereimtheiten gestopert. Folgende Version funktioniert:

Code: Alles auswählen

#!/bin/bash

until [[ "$NAME" =~ ^([A-Za-z0-9äöüß]|[-_.])+$ ]] ; do
echo "Enter NAME"
read NAME
done
echo $NAME
Setzt man den Vergleichstring in doppelte Anführungsstriche, geht's schon nicht mehr. Ebensowenig, wenn die Umlaute und das ß in der zweiten Klammer stehen. Auch die Zeichen in der zweiten Klammer in der ersten unterzubringen, weder mit Maskierung noch ohne, funktioniert nicht.
Desweiteren werden auch keine Klassen wie [:alnum:],[:alpha:] akzeptiert.

Code: Alles auswählen

man bash
war nicht hilfreich. Wo sind die Regexe dokumentiert, die in einem Bashscript zugelassen sind?
Die deutsche Rechtschreibung ist Freeware, d.h. Du darfst sie kostenlos nutzen. Allerdings ist sie keine freie Software, d.h. Du darfst sie nicht ändern oder in veränderter Form weitergeben.

Benutzeravatar
Meillo
Moderator
Beiträge: 9254
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Regexe in Bashscripts

Beitrag von Meillo » 11.01.2010 14:01:34

Bei mir funktionierts sowohl mit Single- als auch mit Doublequotes.

Code: Alles auswählen

[[ "hallo" =~ '^[a-z]+$' ]] && echo matched
Quilmes hat geschrieben:

Code: Alles auswählen

^([A-Za-z0-9äöüß]|[-_.])+$
Die Alternation ist doch unnötig. Weshalb nicht:

Code: Alles auswählen

^[A-Za-z0-9äöüß_.-]+$
(Bindestrich am Ende!)

(btw: Die großen Umlaute fehlen.)
Use ed once in a while!

Benutzeravatar
Quilmes
Beiträge: 87
Registriert: 11.04.2008 23:25:52

Re: Regexe in Bashscripts

Beitrag von Quilmes » 11.01.2010 14:15:11

Meillo hat geschrieben: Die Alternation ist doch unnötig. Weshalb nicht:

Code: Alles auswählen

^[A-Za-z0-9äöüß_.-]+$
(Bindestrich am Ende!)

(btw: Die großen Umlaute fehlen.)
Weil, wie ich im Eingangsposting schon schrieb, der String nicht akzeptiert wird, und ich das Script nur mit STRG-C abbrechen kann. War nur ein Workaround, mit dem es geht. Mir ist schon klar, daß es sich nicht um eleganten Code handelt. Nur verhielten sich mehrere Regexe seltsam, s.o.. Um auf Dein Beispiel zurückzukommen, per copy-and-paste folgenden Code getestet:

Code: Alles auswählen

#!/bin/bash

until [[ "$NAME" =~ "^[a-z]+$" ]] ; do
echo "Enter NAME"
read NAME
done
echo $NAME
aber:

Code: Alles auswählen

$ ./test.sh 
Enter NAME
qwertz
Enter NAME
asdfg
Enter NAME
^C
$

der Vollständigket halber:

Code: Alles auswählen

$ bash --version
GNU bash, Version 4.0.33(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
Die deutsche Rechtschreibung ist Freeware, d.h. Du darfst sie kostenlos nutzen. Allerdings ist sie keine freie Software, d.h. Du darfst sie nicht ändern oder in veränderter Form weitergeben.

Benutzeravatar
Meillo
Moderator
Beiträge: 9254
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Regexe in Bashscripts

Beitrag von Meillo » 11.01.2010 14:24:09

Quilmes hat geschrieben:

Code: Alles auswählen

#!/bin/bash

until [[ "$NAME" =~ "^[a-z]+$" ]] ; do
echo "Enter NAME"
read NAME
done
echo $NAME
Gut dass du den Code gepostet hast.

Ich tippe, dass es überhaupt nicht an der RegExp liegt, sondern daran, dass der Schleifeninhalt einmal in einer Subshell ausgeführt wird und das andere Mal nicht.
Use ed once in a while!

Benutzeravatar
Quilmes
Beiträge: 87
Registriert: 11.04.2008 23:25:52

Re: Regexe in Bashscripts

Beitrag von Quilmes » 11.01.2010 14:35:23

:?:
Die deutsche Rechtschreibung ist Freeware, d.h. Du darfst sie kostenlos nutzen. Allerdings ist sie keine freie Software, d.h. Du darfst sie nicht ändern oder in veränderter Form weitergeben.

Benutzeravatar
Meillo
Moderator
Beiträge: 9254
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Regexe in Bashscripts

Beitrag von Meillo » 11.01.2010 14:55:06

Teste doch die RegExps für sich (siehe mein Beispielcode von oben). Dann wirst du sehen, dass sie wie erwartet funktionieren. Dein Problem hat also nichts mit den RegExps zu tun.

Das eigentliche Problem ist, dass komplexere Statements (wie while und until) in Subshells ausgeführt werden. Wenn du also im Body mit read(1) eine Variable anlegst, dann ist die außerhalb der Schleife (und wie's aussieht auch im Kopf) nicht bekannt. Die bash und manche anderen Shells vermeiden die Subshell wenn es ihnen möglich ist. Somit lässt sich erklären warum es manchmal geht und manchmal nicht.

Ich kann leider nicht versichern, dass es wirklich daran liegt, vermute es aber stark. Habe leider gerade nicht genug Zeit um näher zu testen.

Aber jetzt hast du zumindest mal Stichworte um eigene Recherchen anzustellen. Und vielleicht weißt noch jemand anderes mehr.
Use ed once in a while!

Benutzeravatar
Duff
Beiträge: 6321
Registriert: 22.03.2005 14:36:03
Wohnort: /home/duff

Re: Regexe in Bashscripts

Beitrag von Duff » 11.01.2010 15:04:44

Bei mir funktioniert die Regex nur, wenn ich die Quotes weglasse!

Code: Alles auswählen

root@homer:~# [[ "hallo" =~ ^[a-z]+$ ]] && echo matched
matched
root@homer:~# [[ "hallo" =~ "^[a-z]+$" ]] && echo matched
root@homer:~# [[ "hallo" =~ '^[a-z]+$' ]] && echo matched
root@homer:~#
Oh, yeah!

Benutzeravatar
Quilmes
Beiträge: 87
Registriert: 11.04.2008 23:25:52

Re: Regexe in Bashscripts

Beitrag von Quilmes » 11.01.2010 15:13:09

Code: Alles auswählen

:~$ [[ "hallo" =~ '^[a-z]+$' ]] && echo matched
:~$ [[ "hallo" =~ ^[a-z]+$ ]] && echo matched
matched
:~$ [[ "hallo" =~ "^[a-z]+$" ]] && echo matched
:~$ [[ "hallo" =~ ^([A-Za-z0-9äöüß]|[-_.])+$ ]] && echo matched
matched
:~$ [[ "hallo" =~ ^([A-Za-z0-9äöüß-_.])+$ ]] && echo matched
:~$ [[ "hallo" =~ ^([A-Za-z0-9äöüß\-\_\.])+$ ]] && echo matched
:~$ 
Die deutsche Rechtschreibung ist Freeware, d.h. Du darfst sie kostenlos nutzen. Allerdings ist sie keine freie Software, d.h. Du darfst sie nicht ändern oder in veränderter Form weitergeben.

Benutzeravatar
Meillo
Moderator
Beiträge: 9254
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Regexe in Bashscripts

Beitrag von Meillo » 11.01.2010 15:22:09

Manpage zur bash hat geschrieben: An additional binary operator, =~, is available, with the same precedence as == and !=. When it is used, the string to
the right of the operator is considered an extended regular expression and matched accordingly (as in regex(3)). The
return value is 0 if the string matches the pattern, and 1 otherwise. If the regular expression is syntactically incor‐
rect, the conditional expression's return value is 2. If the shell option nocasematch is enabled, the match is performed
without regard to the case of alphabetic characters. Any part of the pattern may be quoted to force it to be matched as
a string.
Substrings matched by parenthesized subexpressions within the regular expression are saved in the array vari‐
able BASH_REMATCH. The element of BASH_REMATCH with index 0 is the portion of the string matching the entire regular
expression. The element of BASH_REMATCH with index n is the portion of the string matching the nth parenthesized subex‐
pression.
Ich hatte schlechte Testdaten (= keine Metazeichen), deshalb ging's bei mir immer.

Quilmes hat geschrieben:

Code: Alles auswählen

:~$ [[ "hallo" =~ ^([A-Za-z0-9äöüß]|[-_.])+$ ]] && echo matched
matched
:~$ [[ "hallo" =~ ^([A-Za-z0-9äöüß-_.])+$ ]] && echo matched
:~$ 
Bei mir matchen beide.

Beachte bitte, dass der Bindestring am Ende der Zeichenklasse stehen muss, damit er literal ist.

Es könnte an den Locales liegen. Teste mal ohne die Umlaute.
Use ed once in a while!

Benutzeravatar
Quilmes
Beiträge: 87
Registriert: 11.04.2008 23:25:52

Re: Regexe in Bashscripts

Beitrag von Quilmes » 11.01.2010 15:45:49

Code: Alles auswählen

:~$ [[ "hallo" =~ ^([A-Za-z0-9äöüß-_.])+$ ]] && echo matched
:~$ [[ "hallo" =~ ^([A-Za-z0-9äöüß_.-])+$ ]] && echo matched
matched
:~$ [[ "hallo" =~ ^([A-Za-z0-9-_.])+$ ]] && echo matched
:~$ 
Demnach hat es mit der Reihenfolge der Sonderzeichen zu tun. Minus am Ende tut's nicht.

Besten Dank soweit.

Was mir aber unklar bleibt:

Code: Alles auswählen

$ [[ "hallo" =~ ^[:alnum:]+$ ]] && echo matched
:~$ 
Kann aber erst morgen auf Rückmeldungen reagieren.
Die deutsche Rechtschreibung ist Freeware, d.h. Du darfst sie kostenlos nutzen. Allerdings ist sie keine freie Software, d.h. Du darfst sie nicht ändern oder in veränderter Form weitergeben.

Benutzeravatar
Meillo
Moderator
Beiträge: 9254
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Regexe in Bashscripts

Beitrag von Meillo » 11.01.2010 16:25:08

Quilmes hat geschrieben:

Code: Alles auswählen

:~$ [[ "hallo" =~ ^([A-Za-z0-9äöüß-_.])+$ ]] && echo matched
Die RegExp enthält den Zeichenbereich von ß bis _, und der ist ungültig weil ß nach _ kommt. Deshalb schlägt es fehl.
Quilmes hat geschrieben:

Code: Alles auswählen

:~$ [[ "hallo" =~ ^([A-Za-z0-9äöüß_.-])+$ ]] && echo matched
matched
Diese RegExp ist valide, weil das Minus am Ende literal (als das Zeichen Minus) gewertet wird.
Quilmes hat geschrieben:

Code: Alles auswählen

:~$ [[ "hallo" =~ ^([A-Za-z0-9-_.])+$ ]] && echo matched
Diese RegExp ist nicht erlaubt weil bei 0-9-_ nicht klar ist ob 0-9 oder 9-_ als Bereich angesehen werden soll. Deshalb schlägt es fehl.


Demnach hat es mit der Reihenfolge der Sonderzeichen zu tun. Minus am Ende tut's nicht.
Wenn du das Minus literal meinst, dann musst du es ans Ende der Zeichenklasse packen, sonst wird es als Bereichssonderzeichen angesehen.
Was mir aber unklar bleibt:

Code: Alles auswählen

$ [[ "hallo" =~ ^[:alnum:]+$ ]] && echo matched
:~$ 
Es fehlen die Klammern der Zeichenklasse. [:alnum:] wird als Ganzes (inkl. eckigen Klammern) durch die enthaltenen Zeichen ersetzt. Wenn diese in einer Zeichenklasse stehen sollen, dann musst du die eckigen Klammern der Zeichenklasse drum rum machen:

Code: Alles auswählen

[[ "hallo" =~ ^[[:alnum:]]+$ ]] && echo matched
Ist ein bisschen verwirrend.
Use ed once in a while!

Benutzeravatar
Duff
Beiträge: 6321
Registriert: 22.03.2005 14:36:03
Wohnort: /home/duff

Re: Regexe in Bashscripts

Beitrag von Duff » 11.01.2010 16:29:39

Quilmes hat geschrieben:
Was mir aber unklar bleibt:

Code: Alles auswählen

$ [[ "hallo" =~ ^[:alnum:]+$ ]] && echo matched
:~$ 
Es muss so lauten:

Code: Alles auswählen

root@homer:~# [[ "hallo" =~ ^[:alnum:]+$ ]] && echo matched
root@homer:~# [[ "hallo" =~ ^[[:alnum:]]+$ ]] && echo matched
matched
Zuletzt geändert von Meillo am 11.01.2010 16:38:31, insgesamt 1-mal geändert.
Grund: Fehlenden Tag ergänzt
Oh, yeah!

chrisbra
Beiträge: 122
Registriert: 19.10.2005 09:36:09
Wohnort: Sachsen-Anhalt
Kontaktdaten:

Re: Regexe in Bashscripts

Beitrag von chrisbra » 11.01.2010 16:46:30

bash3? Ab 3.2 dürfen keine quotes mehr vorhanden sein, wenn der Ausdruck als Regex ausgewertet werden soll. Ähnliches Problem hab ich in irgendeinem anderen Thread bereits angesprochen.
Siehe auch E14 in der Bash FAQ
Zuletzt geändert von chrisbra am 11.01.2010 16:52:57, insgesamt 1-mal geändert.
Meine Whishlist
:wq!

chrisbra
Beiträge: 122
Registriert: 19.10.2005 09:36:09
Wohnort: Sachsen-Anhalt
Kontaktdaten:

Re: Regexe in Bashscripts

Beitrag von chrisbra » 11.01.2010 16:49:16

Quilmes hat geschrieben:

Code: Alles auswählen

:~$ [[ "hallo" =~ ^([A-Za-z0-9äöüß-_.])+$ ]] && echo matched
:~$ [[ "hallo" =~ ^([A-Za-z0-9äöüß_.-])+$ ]] && echo matched
matched
:~$ [[ "hallo" =~ ^([A-Za-z0-9-_.])+$ ]] && echo matched
:~$ 
Demnach hat es mit der Reihenfolge der Sonderzeichen zu tun. Minus am Ende tut's nicht.
[/code]
äöüß sind in einer deutschen locale bereits mit a-z enthalten.

Code: Alles auswählen

$ [[ "hallo" =~ ^[:alnum:]+$ ]] && echo matched
:~$ 
[/quote]
Das matched ja auch auf Zeilenanfang und beliebig viele der Zeichen :, a, l, n, u, oder m aber mindestens 1.

[Update]: ARGl, ich hasse Foren Syntax..
Meine Whishlist
:wq!

Benutzeravatar
Meillo
Moderator
Beiträge: 9254
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Regexe in Bashscripts

Beitrag von Meillo » 11.01.2010 16:51:46

chrisbra hat geschrieben:[Update]: ARGl, ich hasse Foren Syntax..
Dafür gibt's den Vorschau-Button. Dann kann man das nämlich gleich korrigieren.
Use ed once in a while!

Antworten