Sed od. Awk - Ersetzen unbekannter parameter

J

JulianB

Hallo liebes Forum,

tja mein erster Post gleich ne Frage. Sorry.

Ich habe ein Textfile indem sich verschiedene Strings befinden. Diese String muss ich nach einem bestimmten Suchparameter durchforsten, Wenn ich diesen Parameter gefunden habe muss ich in dem gleichen Satz die 3, hinter dem Parameter stehenden, Wörter durch einen Platzhalter ersetzen.

Z.B.

Text text SFTP_CP_NU Wort1 Wort2 Wort3 Pfad Pfad Dateiname.dat

So ich weiß das sich in dem Satz SFTP_CP_NU befindet, d.h. ich muss danach suchen. Ersetzen will ich aber Wort1-3, diese sind durch leerzeichen getrennt.

Ich weiß nur, diese drei zu ersetzenden Wörter stehen hinter SFTP_CP_NU, es sind immer 3, sie sind durch blanks getrennt und hinter dem dritten folgen weitere Angaben.

Jetzt der größte Punkt warum ich nach Hilfe schreie: Ich habe weder von Sed noch von Awk Ahnung ^^. War immer mit Perl zufrieden, aber das kann ich jetzt nicht nutzen.

Kann mir jemand helfen???

Liebe Grüße,
Julian
 
Wenn Du es mit perl nicht machen kannst, klingt das sehr nach Hausaufgabe. Daher nur ein paar hinweisende Fragen
- wie wuerdest Du es denn mit Perl machen?
- wieviel weisst Du ueber regulaere Ausdruecken?
- Wenn man in sed einen regulaeren Ausdruck mit \(...\) umschliesst, kann man ihn mit \# referenzieren, wobei '#' die Anzahl der \(..\) Ausdruecke zaehlt.
 
Nein mit Hausaufgabe hat das rein garnichts zu tun. Ich brauche das Script für die bearbeitung von Logs auf Solarismaschinen. In Perl würde ich das ganze so lösen:

Code:
use strict;
use warnings;

my $buffer = '';
my $filename = $ARGV[0];
my $replace = '';
my $SUP = 'Platzhalter';
my $change = '';
my $new = '';
my @data;

    foreach $replace(@data)
    {
       if(index($replace,"SFTP_CP_NU") != -1)
       {
        $replace =~ m/^(.*)("SFTP_CP_NU" {1})([A-Za-z0-9_\.\,\+\*-]*)( {1}[A-Za-z0-9_\.\,\+\*-]*)( {1}[A-Za-z0-9_\.\,\+\*-]*)( {1}.*)$/;
        local $FIRST=$1;
        local $FTP=$2;
        local $LAST=$6;
        $buffer=$FIRST;
        $buffer.=$FTP;
        $buffer.=$SUP;
        $buffer.=$LAST;
        $buffer.="\n";
        $replace = $buffer;
       }
    }


So in etwa jedenfalls, den gesamten Code kann ich leider nicht posten. Nur jetzt mit SED und AWK habe ich keine ahnung....

Aber nochmal, keine Hausaufgaben, aber Perl ist trotzdem nicht möglich.

Liebe Grüße,

Julian

PS: Das was du in meinem Perl Beispiel siehst ist alles was ich von RegEx weiß, sprich nicht viel, aber ich glaube einigermaßen genug.

___________________________________

Ergänzung:

Mit Awk bin ich jetzt so weit, das ich den gewünschten Parameter finde:

Code:
cat test |awk '
{n=split($0,Array," ")
for(i=1; i<NF; i++)
{
if(Array[i] == "SFTP_CP_NU")
{
print $i
}
}
}'

Jetzt muss ich nur die darauf folgenden 3 Felder bearbeiten, sprich deren Inhalt durch einen anderen Inhalt ersetzen. Geht das mit Awk??? (Solaris, ksh)
 
Zuletzt bearbeitet von einem Moderator:
Hallo
Das geht wunderbar mit sed:
Code:
$ cat file
text Suchtext Wort1 Wort2 Wort3 foo bar foobar
text text Wort1 Wort2 Wort3 foo bar foobar
sed -e '/Suchtext/s/\(.* Suchtex[[:space:]]\+\)\([^[:space:]]*[[:space:]]\{1\}\)\{3\}\(.*\)$/\1Rep1 Rep2 Rep3 \3/'
text Suchtext Rep1 Rep2 Rep3 foo bar foobar
text text Wort1 Wort2 Wort3 foo bar foobar

POSIX:
Code:
[[:space:]]
statt Leerzeichen, sollte also auch auf Solaris laufen.

Merke: Negationen erleichtern bei RegExp oft das Leben. ;)
Hier nicht Leerzeichen
Code:
[^[:space:]]

Gruß Wolfgang
 
Der Perl code ist ja auch schon recht nahe an einer Loesung. Ein wichtiger Unterschied ist, dass man Bloecke an regulaeren Ausdruecken mit \(...\) referenzieren kann, waehrend es in Perl mit einfachen Klammen zu gehen scheint.
 
Ein wichtiger Unterschied ist, dass man Bloecke an regulaeren Ausdruecken mit \(...\) referenzieren kann, waehrend es in Perl mit einfachen Klammen zu gehen scheint.

Korrekt in Perl werden die RE's in einfache "()" gesetzt, ein Grund mehr warum ich mit SED wohl nie ganz klar gekommen wäre.

Bin ja letzendlich auch auf Awk gekommen, ich bin nunmal leider mehr für eine C/C++ Schreibweise geboren als für ewig lange RE's ^^. Aber ich will trotz alledem es mit SED versuchen.

Also Wolfgang:

Erstmal vielen vielen Dank für die sehr schnelle Antwort, ich werde es sofort austesten und mich dann melden.
PS: Negation in RE's kenne ich ^^.

Liebe Grüße,

Julian
.
.
.
EDIT (autom. Beitragszusammenführung) :
.

Hallo Wolfgang,

ich habe dein Code eben getestet, nur irgendwie tut sich garnichts. Ich habe ihn angepasst (also nur Suchtext durch SFTP_CP_NU ersetzt). Doch ich bekomme weder Fehlermeldungen noch bekomme ich ein Ergebnis.

Die Datei wird ausgegeben, geändert hat sich nichts.

Das geht wunderbar mit sed:
Code:
sed -e '/Suchtext/s/\(.* Suchtex[[:space:]]\+\)\([^[:space:]]*[[:space:]]\{1\}\)\{3\}\(.*\)$/\1Rep1 Rep2 Rep3 \3/'

Zu deinen RegEx habe ich allerdings eine Frage, irgendwas will da nicht in meinen Kopf.

Wenn ich das richtig verstehe suchst du mit SED nach dem Wort "Suchtext" Zeile f. Zeile, wenn "Suchtext" in Zeile vorkommt, rufst du deine Regex auf, diese findet "Suchtext"+Blank und danach beliebig viele Nichtblanks bis wieder ein Blank auftaucht
Code:
 \([^[:space:]]*[[:space:]]\
das ganze 3 mal {3} bis zum Zeilenende $/.

Okidoki, nur wie funktioniert der letzte Teil deiner Regex??? Ersetzt du den geklammerten Ausdruck vor Klammer 3 durch Rep1 -3?? Magst du mir den Teil vll einmal erklären???

Danke.
 
Zuletzt bearbeitet von einem Moderator:
Hallo

\1 ist der Inhalt von der ersten Klammer, also der Text vor Suchtext + der Suchtext selbst + ein Space.
Dann füge ich drei Worte ein REP(LACE) 1 bis 3
Dann häng ich den Text nach \2 Klammerpaar 2 ein.

Die Backreferenzen funktionieren bei sed genau wie bei Perl $1 bei perl entspricht hier \1

Wolfgang
 
Hallo Wolfgang,

okay, aber warum klappt das einfach nicht. Ich habe auf meiner Solarismaschine sogar deinen Probetext benutzt. Aber mit deinen RegEx bekomme ich zwar keine Fehlermeldung aber wenn ich den durch SED geänderten Inhalt in eine zweite Datei schreibe test1>test2 dann steht in test2 genau dasselbe wie in test1, sprich es hat sich nichts geändert...ich verstehe das nicht. Ich habe schon an deinem Befhel alle [[:space:]] durch normale Blanks ersetzt, daran lag es nicht. Ich habe auch den Befehl /g gesetzt. Auch das wars nicht. Irgendwie findet er die Zeile nicht, bzw. sucht das falsche.

Code:
e '/Suchtext/s/\(.*

Kann man hier nicht eigentlich das /Suchtext/ einfach weglassen???

LG
 
Hallo
Ja, das kannst du auch weglassen.
Ist nur für Performance relevant, da im Falle des Nichtvorkommens garnicht erst die RegExp-Engine angeworfen wird.

Aber dann teste doch erstmal, ob dein SUCHTEXT überhaupt gefunden wird?

Code:
sed -ne '/SUCHTEXT/p' input
Hier wird die Zeile nur ausgegeben, wenn SUCHTEXT gefunden wird.

Wolfgang
 
Hey Wolfgang,

erstmal vielen vielen Dank für die Superhilfe die ich hier bekomme. Das erlebe ich sehr sehr selten wenn ich eine Frage in einem Forum stelle. Wirklich Top.

Back to Topic:

Wenn ich nur nach dem Suchbegriff parse bekomme ich genau die richtige Zeile ausgegeben, daran kann es schonmal nicht liegen....

Wie jetzt weiter? Ich grübel mir gerade die Birne heiß :think:

Liebe Grüße aus dem hohen Norden,

Julian

.
.
.
EDIT :
.

Mir sind gerade ein paar Sache aufgefallen:

Wenn ich vor dem Suchwort in der Klammer od. in einer anderen Klammer .* stehen habe, dann findet er in der gesamten Zeile nichts.

Sprich bei:
Code:
\(.* SFTP_CP_NU\)

wird nichts angezeigt im Gegensatz zu:

Code:
\(SFTP_CP_NU\)

Jetzt habe ich auch noch das Problem wenn ich hinter einen geklammerten Ausdruck wie Wolfgang gesagt hat {3} setze, scheint diese garnicht wiederholt zu werden...kann man geklammerte Ausdrücke überhaupt wiederholen, oder gilt das {n} nur für Zeichen?

LG Julian
.
.
.
EDIT (autom. Beitragszusammenführung) :
.

Na Wolfgang, spaß vergangen??? Nein, war nur ein Scherz ;)

So was habe ich rausbekommen:

Solaris scheint die eckigen Klammern [] nicht zu mögen.

Die RegEx scheint von hinten (rechts) abgelaufen zu werden, sprich:

Code:
cat file

Txt1 txt2 Suchwort txt3 txt4 txt5 txt6 txt7 txt8 txt9

\(Suchwort\)   \{1\}\(.*\)    \{1\}\(.*\)    \{1\}\(.*\)

/1 enthält nun das Suchwort
/2 enthält txt3
/3 enthält txt4-8
/4 enthält txt9

Wieso das???? Ich verstehe das nicht, bei Perl wäre jetzt in /1 das Suchwort in /2 wäre txt3 in /3 wäre txt4 in /4 wäre txt5 usw...

Naja ich prussel hier noch weiter...

LG
.
.
.
EDIT (autom. Beitragszusammenführung) :
.

So meine Lieben, insbesondere Wolfgang,

Ich habe es tatsächlich gelöst bekommen, ohne Eure Hilfe aber sicher nicht!!!

Code:
s/\.*\( \{1\}SFTP_CP_NU\) \{1\}\([A-Za-z0-9_\.\,\+\*-]* \{1\}[A-Za-z0-9_\.\,\+\*-]* \{1\}[A-Za-z0-9_\.\,\+\*-]*\) \{1\}\(.*\)$/\1 XXX XXX XXX \3/

Nicht unbedingt die schönste Variante, wie ich mir denke. Aber sie funktioniert UND sie ist absolut Solariskompatibel ^^.

Vielen Dank nochmal,

Julian.

...ACHJA:

Gibt es soetwas wie -i auch auf Solaris????

Cya
 
Zuletzt bearbeitet von einem Moderator:
So, nun meine Antwort.
Die Lust ist mir nicht vergangen, war schlicht und ergreifend Unterwegs.

Zum Thema:
Habe hier kein Solaris zur Verfügung, deshalb kenne ich die von dir verwendete sed.Version auch nicht.
Möglicherweise unterstützt ja das sed bei Solaris nicht die erweiterten RE-Funktionen.
Mein Vorschlag ist insofern nur als Denkanstoß zu nehmen, was du ja nun auch gemacht hast.
Mich würde schonmal interessieren, wie negierte Zeichenklassen bei deinem sed verwendet werden.
Laut Manpage im Netz:
1.4 A non-empty string of characters enclosed in square
brackets ([]) is a one-character RE that matches any
one character in that string. If, however, the first
character of the string is a circumflex (^), the one-
character RE matches any character except new-line and
the remaining characters in the string. The ^ has this
special meaning only if it occurs first in the string.
The minus (-) may be used to indicate a range of con-
secutive characters; for example, [0-9] is equivalent
to [0123456789]. The - loses this special meaning if
it occurs first (after an initial ^, if any) or last
in the string. The right square bracket (]) does not
terminate such a string when it is the first character
within it (after an initial ^, if any); for example,
[]a-f] matches either a right square bracket (]) or
one of the ASCII letters a through f inclusive. The
müsstest du also das Leerzeichen mit [^ ] darstellen können.


Aber eventuell kannst du ja mal schauen, ob GNU sed unter deinem Solaris installiert ist.
Müsstest du dann mit vollem Pfad aufrufen.

Gruß Wolfgang
 
Jop stimmt, habs nochmal getestet die Negation von Blanks [^ ] funktioniert sehr gut.

Danke an euch alle und :CLOSED: ;)
 
Zurück
Oben