Bash-Aufgabe

Tronar

aus Überzeugung altmodisch
Kein ernstzunehmendes Problem, aber ich bin halt neugierig. Als Modell betrachten wir die folgende Aufgabe:
Ich soll in einem String jede Zahl in Klammern setzen.
Mit »sed« ist das ganz einfach:
Code:
~$ sed -r 's/[.0-9]+/(&)/g'
blabla 1234 und 3.14159 nebst 5.55 usw.
blabla (1234) und (3.14159) nebst (5.55) usw(.)
Okay, da müßte man noch den letzten Punkt irgendwie herausnehmen, aber das interessiert im Moment hier nicht. Was mich interessiert: Geht das auch mit Shell-Built-Ins?
Mit der ksh kann ich es:
Code:
~$ text="blabla 1234 und 3.14159 nebst 5.55 usw."
~$ echo ${text//+([.0-9])/(\1)}
blabla (1234) und (3.14159) nebst (5.55) usw(.)
Aber das macht die Bash nicht. Meine Frage: Geht so etwas überhaupt in der Bash? Ich meine, ohne ein 30-Zeilen-Skript zu verfassen.
 
Geht meines Wissens mit Bash nicht, da die Ersetzung mit ${var//pattern/replacement} keine regexp Implementierung darstellt, sondern nur besseres globbing (extglob). Deshalb kennt Bash wohl kein Capturing über () und somit auch keine Referenzierung von Capture Groups über \1.

Ksh hingegen verfügt über vollwertige regexp.

Gruß
 
Für den Punkt müsstest du halt sagen, dass ein Punkt zwar optional, aber nur in Verbindung mit einer Ziffer auftreten darf.

Code:
([0-9]+\.)?[0-9]+

bzw. wenn auch sowas wie .95 gehen soll:

Code:
([0-9]+)?\.?[0-9]+
 
vto, da liegst Du leicht falsch. Meine obige Anweisung für die Ksh war ebenfalls kein Regexp, sondern ein Shell-Glob. In der Ksh gibt es aber die Möglichkeit, die einzelnen gematchten Komponenten eines Shell-Glob mit "\1" usw. zu referenzieren. In der Bash wäre dafür wiederum ein Array $BASH_REMATCH[...] zuständig, aber das funktioniert nur für reguläre Ausdrücke und folglich nicht in diesem Replacement-String.
Reguläre Ausdrücke werden sowohl in der Bash als auch in der Ksh unterstützt, aber nur in sehr speziellen Konstrukten. In beiden Shells in der Doppelklammer
Code:
[[ X =~ Y ]] && echo 'match!'
Hier wird Y als ERE ausgewertet. In der Ksh gibt es zusätzlich noch das Konstrukt $(E:bla), das einen ERE (oder basic oder Perl-Typ wahlweise) "bla" in ein Shell-Glob-Pattern hineinflickt.

Wie auch immer, meine Frage zielte darauf ab, ob es irgendeine alternative Möglichkeit in der Bash gibt. Das kann ich nun selbst beantworten, aber ziemlich unelegant (wobei ich TCMs Hinweis der Einfachheit halber ignoriere):
Code:
text="blabla 1234 und 3.14159 nebst 5.55 usw."
while [[ "$text" =~ ([^.0-9]*)([.0-9]+) ]]
do echo -n "${BASH_REMATCH[1]}(${BASH_REMATCH[2]})"
text="${text#${BASH_REMATCH[1]}${BASH_REMATCH[2]}}"
done; echo "$text"
Dann lieber "sed"!
 
Bitte! Eine kleine Korrektur noch:
Die Syntax für das File name globbing mit ERE in der Ksh lautet nicht $(E:bla), sondern ~(E:bla); das hatte ich falsch in Erinnerung. Für basic RE dann ~(G:bla) und für Perl-RE ~(P:bla) - und noch ein paar weitere Varianten.
 
Zurück
Oben