ubuntuusers.de

Linux: bash: Sed

Status: Gelöst | Ubuntu-Version: Xubuntu 20.04 (Focal Fossa)
Antworten |

Umaash

Anmeldungsdatum:
7. Juni 2016

Beiträge: 123

Ist es möglich, von sed eine Rückmeldung zu erhalten, ob das Muster gefunden werden konnte oder nicht? So etwas wie ... Wenn sed das Suchmuster gefunden hat gibt er "1" zurück, wenn nicht "0", oder ähnlich?

1
echo "Some [text] with *special* characters" | sed 's/with/hit/g'

Eine Antwort würde mich freuen. Besten Dank.

dingsbums

Anmeldungsdatum:
13. November 2010

Beiträge: 3782

echo "Some [text] with *special* characters" | sed --debug -e 's/with/hit/g' | grep -B 3 -A 4 -P '^MATCHED'

Siehe https://unix.stackexchange.com/questions/492871/any-way-to-have-a-verbose-mode-or-debug-mode-with-sed

wxpte

Anmeldungsdatum:
20. Januar 2007

Beiträge: 1388

Das könnte man dann noch so weit abändern, dass nur dann eine Ausgabe erfolgt, wenn der übergebene String modifiziert worden ist:

echo "Some [text] with *special* characters" | sed --debug -e 's/with/hit/g' | grep -A4 '^MATCHED' | sed -n '$p'

Wenn es dagegen nur darum geht, ob ein bestimmtes Muster gefunden wurde, ist ein reines grep ohnehin der passendere Befehl:

echo "Some [text] with *special* characters" | grep -Fq 'with' || echo 'Der Ausdruck wurde nicht gefunden.'

(Wozu man bei grep für so eine einfache regex wie ^MATCHED die Option -P benötigt, ist mir auch nicht so ganz klar).

Umaash

(Themenstarter)

Anmeldungsdatum:
7. Juni 2016

Beiträge: 123

Ich sehe, dass in beiden Fällen grep verwendet wurde. Ich habe eigentlich auf eine sed-native Variante gehofft.

Denn ich habe bereits Mühe mit dem Befehl Sed, damit richtig escaped wird, so dass das Muster, dass ich suchen will nicht verfälscht wird. Ich vermute mal, dass bei der Verwendung von grep wieder anders escaped wird. Richtig? Das heisst das Escapen, was ich für den Befehl sed vorbereitet habe funktioniert nicht gleichzeitig auch für grep? Oder ist diese Angst unbegründet?

wxpte

Anmeldungsdatum:
20. Januar 2007

Beiträge: 1388

Umaash schrieb:

Ich habe eigentlich auf eine sed-native Variante gehofft.

Das ist wohl Schicksal beim bash-Skripting: außer grep gibt es kaum einen Befehl, der einen ergebnisorientierten Exit-Status zurückliefert. Nicht einmal find ...

Denn ich habe bereits Mühe mit dem Befehl Sed, damit richtig escaped wird, so dass das Muster, dass ich suchen will nicht verfälscht wird. Ich vermute mal, dass bei der Verwendung von grep wieder anders escaped wird. Richtig? Das heisst das Escapen, was ich für den Befehl sed vorbereitet habe funktioniert nicht gleichzeitig auch für grep? Oder ist diese Angst unbegründet?

Eher letzteres. Die regulären Ausdrücke für zu suchende Muster sind für die gesamte bash gleich. Nur bei der Ersetzung gibt es ein paar Besonderheiten: & als Platzhalter für das Muster, nach welchem gesucht worden ist (aber das kennst du ja schon). Oder wenn du bei der Suche gruppierst, kannst du mit \1\2\3 (und so weiter) den Ausdruck neu zusammensetzen. Eine recht ausführliche Beschreibung der regulären Ausdrücke findest du übrigens im Wiki zu grep gleich am Anfang. Zumindest für die Suche in sed gilt das dort geschriebene entsprechend.

Nachtrag: Eine schöne Möglichkeit, das Datumsformat umzubauen:

echo '17.02.2024' | sed -E 's/([0-9]{2})\.([0-9]{2})\.([0-9]{4})/\3-\2-\1/'

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1247

Umaash schrieb:

Ich sehe, dass in beiden Fällen grep verwendet wurde. Ich habe eigentlich auf eine sed-native Variante gehofft.

Doch gibt es. Schau dir mal die "t" und "T" Befehle nach dem "s///" Befehl an. Damit kannst du entweder zu einem benannten Label oder ans Ende hüpfen. Schau mal in der man page.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13174

wxpte schrieb:

Umaash schrieb:

Ich habe eigentlich auf eine sed-native Variante gehofft.

Das ist wohl Schicksal beim bash-Skripting: außer grep gibt es kaum einen Befehl, der einen ergebnisorientierten Exit-Status zurückliefert. Nicht einmal find ...

Das stimmt nicht. Natürlich liefert find einen definierten Exit-Status. Wegen der Komplexität des Befehls (und möglicherweise ausgeführten anderen Befehlen) gibt es halt nur eine Menge Faktoren, die ihn beeinflussen - angefangen von Fehlern im Aufruf bis zu Rückgabewerten von mit "-exec" ausgeführten anderen Prozessen.

Denn ich habe bereits Mühe mit dem Befehl Sed, damit richtig escaped wird, so dass das Muster, dass ich suchen will nicht verfälscht wird. Ich vermute mal, dass bei der Verwendung von grep wieder anders escaped wird. Richtig? Das heisst das Escapen, was ich für den Befehl sed vorbereitet habe funktioniert nicht gleichzeitig auch für grep? Oder ist diese Angst unbegründet?

Eher letzteres. Die regulären Ausdrücke für zu suchende Muster sind für die gesamte bash gleich.

Das ist eine problematische Aussage. Wenn Du Dich auf die bash selber beziehst, stimmt das natürlich. Wobei die bash eher einen untypischen Dialekt von Regulären Ausdrücken versteht. Aber die Regulären Ausdrücke, die grep und andere Werkzeuge nutzen unterscheiden sich z.T. deutlich, was das Escapen und andere Features angeht. Vergleich nur mal das Format von grep mit egrep (bzw. grep -E) und sed mit sed -E. Und dann gibt es noch die Dialekte von Regulären Ausdrücken in ruby, python und - vor allem - perl. Das Buch "Mastering Regular Expressions" behandelt das Thema ziemlich erschöpfend. Ich kann das jedem nur empfehlen, der sich näher mit Regulären Ausdrücken beschäftigen möchte.

Zur ursprünglichen Frage: man baut Reguläre Ausdrücke am besten schrittweise auf und testet immer wieder mit den gewünschten Eingaben. Dann erkennt man recht verlässlich, wo es hakt. Zum Identifizieren eines Treffers kann man eine geklammerte Ersetzung nutzen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ seq 1 10 | sed 's#1#<&>#'
<1>
2
3
4
5
6
7
8
9
<1>0

wxpte

Anmeldungsdatum:
20. Januar 2007

Beiträge: 1388

rklm schrieb:

Das stimmt nicht. Natürlich liefert find einen definierten Exit-Status. Wegen der Komplexität des Befehls (und möglicherweise ausgeführten anderen Befehlen) gibt es halt nur eine Menge Faktoren, die ihn beeinflussen - angefangen von Fehlern im Aufruf bis zu Rückgabewerten von mit "-exec" ausgeführten anderen Prozessen.

Deswegen schrieb ich auch »ergebnisorientiert« – aber ich gebe zu: auch dieser Begriff ist interpretationsfähig. Deswegen ergänze ich an dieser Stelle: mit »ergebnisorientiert« meine ich in diesem Zusammenhang »abhängig davon, ob eine Suche einen Treffer erzielt, oder nicht«.

Vergleich nur mal das Format von grep mit egrep (bzw. grep -E) und sed mit sed -E.

Aber gerade das ist doch das Schöne an grep und sed: die Option -E läuft bei beiden Werkzeugen wunderbar parallel, so dass, je nachdem, ob die Option verwendet wird, der jeweils gleiche Satz der regex vorliegt. Lediglich für grep -F gibt es bei sed keine Entsprechung.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17604

Wohnort: Berlin

Umaash schrieb:

Ist es möglich, von sed eine Rückmeldung zu erhalten, ob das Muster gefunden werden konnte oder nicht? So etwas wie ... Wenn sed das Suchmuster gefunden hat gibt er "1" zurück, wenn nicht "0", oder ähnlich?

1
echo "Some [text] with *special* characters" | sed 's/with/hit/g'

Zum Testen hilft vielleicht schlicht eine Ausgabe statt einer Rückgabe:

1
echo "Some [text] with *special* characters" | sed -n 's/with/hit/gp'

Eine Rückgabe, wenn man nur testen will, ob es matcht, ließe sich so realisieren:

1
2
3
4
5
t530:~ 🐧> echo "Some [text] wath *special* characters" | sed '/with/q111'; (($? == 111)) && echo hit 
Some [text] wath *special* characters
t530:~ 🐧> echo "Some [text] with *special* characters" | sed '/with/q111'; (($? == 111)) && echo hit 
Some [text] with *special* characters
hit

, bricht aber eben nach dem ersten Match ab (quit).

kB Team-Icon

Supporter, Wikiteam
Avatar von kB

Anmeldungsdatum:
4. Oktober 2007

Beiträge: 9627

Wohnort: Münster

Umaash schrieb:

Ist es möglich, von sed eine Rückmeldung zu erhalten, ob das Muster gefunden werden konnte oder nicht? So etwas wie ... Wenn sed das Suchmuster gefunden hat gibt er "1" zurück, wenn nicht "0", oder ähnlich?

Diese Aufgabe erledigt man üblicherweise mit grep, aber es geht auch mit sed, jedenfalls so ähnlich:

$ echo anton | sed -n '/o/ p'
anton
$ echo antOn | sed -n '/o/ p'
$ 

Wenn das Suchmuster (hier beispielhaft /o/ für alle Zeilen, welche ein kleines o enthalten) gefunden wird, werden alle passenden Zeilen ausgegeben. Wenn es nicht gefunden wird, wird nichts ausgegeben.

Durch kompliziertere sed-Programme kann man natürlich nach dem ersten Fund abbrechen oder etwas anderes ausgeben als die gefundene Zeile. Dann muss man natürlich die etwas absonderliche Programmiersprache erlernen, welche sed interpretiert.

Die Umwandlung in einen Ergebniscode funktioniert mit einem nachgeschalteten grep, aber dann verwendet man besser grep selbst zur Lösung der Aufgabe.

wxpte

Anmeldungsdatum:
20. Januar 2007

Beiträge: 1388

user_unknown schrieb:

Eine Rückgabe, wenn man nur testen will, ob es matcht, ließe sich so realisieren:

1
2
3
4
5
t530:~ 🐧> echo "Some [text] wath *special* characters" | sed '/with/q111'; (($? == 111)) && echo hit 
Some [text] wath *special* characters
t530:~ 🐧> echo "Some [text] with *special* characters" | sed '/with/q111'; (($? == 111)) && echo hit 
Some [text] with *special* characters
hit

, bricht aber eben nach dem ersten Match ab (quit).

Ja, aber spätestens hier stellt sich die Frage, warum man es so kompliziert machen wollen würde, wenn doch auch ein einfaches grep -q denselben Zweck erfüllt.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17604

Wohnort: Berlin

wxpte schrieb:

user_unknown schrieb:

Eine Rückgabe, wenn man nur testen will, ob es matcht, ließe sich so realisieren:

1
2
3
4
5
t530:~ 🐧> echo "Some [text] wath *special* characters" | sed '/with/q111'; (($? == 111)) && echo hit 
Some [text] wath *special* characters
t530:~ 🐧> echo "Some [text] with *special* characters" | sed '/with/q111'; (($? == 111)) && echo hit 
Some [text] with *special* characters
hit

, bricht aber eben nach dem ersten Match ab (quit).

Ja, aber spätestens hier stellt sich die Frage, warum man es so kompliziert machen wollen würde, wenn doch auch ein einfaches grep -q denselben Zweck erfüllt.

Weil es die Vorbereitung eines Sed-Kommandos wäre, das eben nicht nur schaut, ob es matcht, sondern weiteren Hokuspokus wie Ersetzen auslösen soll. Und wg. all der Schalter für grep und sed würde ich einen Ausdruck, der für sed gedacht ist, auch mit sed testen.

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1247

Ok, wenn ihr ein Beispiel mit dem "t" Befehl wollt, hier ist es in "Schönschrift", damit nicht alles in einer Zeile steht:

$ echo "### Ausgabe ###"
$ echo "Some [text] wath *special* characters
und hier eine Zeile ohne das Suchwort
und zuletzt wieder ein wath in der Zeile" | 
sed -n  '
bb
:a
i\Meldung: Text enthält "wath"
bc
:b
p
s/wath/with/
ta
i\Meldung: Text enthält NICHT "wath"
:c
i\neue Zeile'
### Ausgabe ###
Some [text] wath *special* characters
Meldung: Text enthält "wath"
neue Zeile
und hier eine Zeile ohne das Suchwort
Meldung: Text enthält NICHT "wath"
neue Zeile
und zuletzt wieder ein wath in der Zeile
Meldung: Text enthält "wath"
neue Zeile
$ 

tomtomtom Team-Icon

Supporter
Avatar von tomtomtom

Anmeldungsdatum:
22. August 2008

Beiträge: 55345

Wohnort: Berlin

Im Übrigen endete der Support für Xubuntu 20.04 im April 2023.

Umaash

(Themenstarter)

Anmeldungsdatum:
7. Juni 2016

Beiträge: 123

user_unknown schrieb:

wxpte schrieb: Ja, aber spätestens hier stellt sich die Frage, warum man es so kompliziert machen wollen würde, wenn doch auch ein einfaches grep -q denselben Zweck erfüllt.

Weil es die Vorbereitung eines Sed-Kommandos wäre, das eben nicht nur schaut, ob es matcht, sondern weiteren Hokuspokus wie Ersetzen auslösen soll. Und wg. all der Schalter für grep und sed würde ich einen Ausdruck, der für sed gedacht ist, auch mit sed testen.

Ganz genau. Ich will nicht mit grep testen, ob es matcht und danach sed verwenden, mit dem es dann möglicherweise nicht matcht.

Ich habe jetzt die erste Variante ausprobiert von den Vorschlägen und bin damit eigentlich gut gefahren:

1
2
3
4
MusterInDateiVorhandenTest=''
MusterInDateiVorhandenTest=$(sed -n ":a;N;\$!ba;/${ZeilenAktion1Arrey[i]}/ p" "${DateinamenArrey[i]}")
if [ -z "$MusterInDateiVorhandenTest" ]; then
[...]

Besten Dank an alle.

Antworten |