• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

Mit sed Zeilen ändern, die nicht mit "global" anfangen

Calvin

Hacker
Hallo zusammen,

ich habe eine Textdatei, in der ich an jede Zeile etwas anhängen muss. Was angehängt wird, hängt vom ersten Wort der Zeile ab.

  • Wenn Zeile mit "global" beginnt => füge ,, an
  • Wenn Zeile nicht mit "global" beginnt => füge , an

Ich wollte das mit sed machen. Ich tue mich aber mit der Syntax ziemlich schwer. Den ersten Fall habe ich bereits zusammenkopiert. Ich weiß allerdings auch nicht bis ins letzte Detail, was da genau passiert.

Code:
sed -i "/^global/ s|\(.*\)$|\1,,|" meineDatei.txt

Passt das soweit? Zumindest funktioniert es ;) Wie kann man den zweiten Fall machen?
 
Code:
#!/bin/bash

IFS=$'\n'
for zeile in `cat ./blubber.txt`
do
if [[ $zeile =~ ^global ]]
then
    echo $zeile | sed "s/\(.*\)$/\1,,/" >> blab.txt
else
    echo $zeile | sed "s/\(.*\)$/\1,/" >> blab.txt
fi
done
mv blubber.txt blubber.txt~
mv blab.txt blubber.txt
Mit sed kannst Du leider nicht auf "!" "not" testen, das muß immer über den Umweg des if-Konstruktes gemacht werden. Hier die Möglichkeiten von RegEx in sed Leider ist sed da so beschränkt wie die einfache grep-Variante.
 
OP
C

Calvin

Hacker
OK, vielen Dank. Ist wirklich umständlich. Aber wenn es nicht anders geht....

Was macht denn die Zeile?
Code:
IFS=$'\n'
:???:

EDIT
Habe es gefunden. Es sorgt dafür, dass die Schleife zeilenweise läuft (Standard ist 'Leerzeichen')
 
Selbstverständlich kannst Du das Ganze auch mit awk machen, da hab ich mich allerdings noch nicht ganz so reingefuchst. Dabei würdest Du laut des Handbuches auch einen !~ "entspricht nicht" Ausdruck verwenden können.
 

komma4

Member
Geier0815 schrieb:
Mit sed kannst Du leider nicht auf "!" "not" testen

Entschuldige, das geht natürlich auch
Code:
sed -i '/^global /! s/\(.*\)/\1,/g' meineDatei.txt

1) / suche nach ^ Zeilenanfang "global "
2) wenn ! nicht gefunden
3) suche [in dieser Zeile!] alles\(.*\)
4) ersetze durch in 3) gefundenen Inhalt und einem Komma

...und für alle Zeilen, die mit dem Suchbegriff beginnen
Code:
sed -i '/^global /s/$/,,/g' meineDatei.txt
1) finde Zeilen die mit "global " beginnen /^global
2) Ersetzen-Aktion nur auf diese Zeilen, $ Zeilenende
 

spoensche

Moderator
Teammitglied
Code:
sed -ri 's/^[^global].*?\s(.*?)$/\1/g'

Wenn du sed mit dem Parameter -r aufrufst kannst du dir das Escapen der () sparen.
 
@komma4,
wo findet man dieses feature dokumentiert? Mir war nicht klar das man addresses auch als "if" bzw in dem Fall "if-not" verwenden kann und auf der von mir verlinkten gnu-Seite zu sed kann ich darüber auch nichts finden. Aber manchmal bin ich auch nur blind.

@spoensche,
magst Du mir mal deinen sed-Befehl auseinander nehmen? Das ^[^global] leuchtet mir nicht wirklich ein, ebenso wenig das Fragezeichen in s(.*?)$ von dem meiner Meinung nach fehlendem slash zu schweigen, ebenso wie den fehlenden Kommas die angehängt werden sollen.

@Calvin,
da Du keine Fallunterscheidung machen kannst, wirst Du auf jeden Fall bei einem Zweizeiler enden. Und Du solltest dir den Link zu diesem Thread als Kommentar in deinem Skript ablegen, ansonsten stehst Du in 2 Monaten vor deinem eigenen Skript und weißt nicht wirklich wie Du auf diesen Code gekommen bist ;-)
 
OP
C

Calvin

Hacker
@Geier0815
Mit "Einzeiler" meinte ich "zwei Einzeiler" ;) Aber die sed-Kommandos muss ich sowieso dokumentieren. Die sind für mich alle zu kryptisch. Und ich glaube, das geht den meisten auch so. Es ist für mich momentan schwer vorstellbar, dass man sed nutzt/lies, ohne ständig in die Doku zu schauen.
 

abgdf

Guru
Calvin schrieb:
Es ist für mich momentan schwer vorstellbar, dass man sed nutzt/lies, ohne ständig in die Doku zu schauen.
Dann mach' das doch mit Perl oder Python. Lohnt sich sicher mehr, das zu lernen, macht auch mehr Spaß, und gerade Python-Skripte sind besonders gut lesbar (während Perl in dem Punkt sed-ähnlicher und besser für kryptische Einzeiler geeignet ist, wenn man die denn unbedingt haben will).
Perl-Einzeiler:
Code:
perl -pe 'chomp;if(/^global/){$_.=",,\n"}else{$_.=",\n"}' meinedatei.txt
"In-place" wäre stattdessen:
Code:
perl -pe 'chomp;if(/^global/){$_.=",,\n"}else{$_.=",\n"}' -i meinedatei.txt
 
A

Anonymous

Gast
SED ist eine der ältesten Scriptsprachen überhaupt, etwas Nachsicht, die Leute für das das ursprünglich erfunden wurde haben wahrscheinlich alle fließend Assembler gesprochen, und gegenüber Assembler-Programmierung ist SED natürlich ein riesiger Vorteil.

Selbstverständlich geht mit sed auch Entweder/oder, eine von vielen möglichen Lösungen.

Code:
sed  '/^global/s/^\(.*\)$/\1,,/;t;s/^\(.*\)$/\1,/'
Zur Erläuterung:
  • 1. erst wird alles gesucht was am Anfang "global" hat und dort ,, angehängt. (der s-Befehl am Anfang) In jeder so gefunde Zeile wird in diesem Fall eine Ersetzung vorgenommen.
    2. danach der nächste Befehl "t" ist ein bedingter Sprung wenn der s-Befehl vorher eine Ersetzung vorgenommen hat wird gesprungen sonst nicht, da keine Sprungmarke angegeben ist wird zum ScriptEnde gesprungen, damit wird beim Sprung mit der Bearbeitung der nächsten Zeile weitergemacht, der Rest der Sedkommandos also gar nicht mehr auf die aktuelle Zeile angewendet.
    3. der 2. s-Befehl wird jetzt nur noch erreicht wenn der erste s-Befehl keine Ersetzung vornehmen konnte, also am Zeilenanfang nicht "global" steht.

Damit haben wir hier eine einfache Implementierung
Code:
IF "^global"
  THEN
       ... 
  ELSE
       ...


Zugegeben richtige Sed-Programmierung ist oftmals schwierig zu verstehen, wird auch heute nur noch selten geschrieben, sind aber immer wieder interessant, da man sich beim Schreiben wirklich noch richtige Lösungswege selber einfallen lassen muss, da man nur 2 Buffer und ca. 20 ganz primitiv und elementar arbeitende Befehle (alle Befehlesnamen sind nur ein einziger Buchstabe) zur Verfügung hat. Das man da öfter mal ins Buch schauen muss ist normal, aber irgendwann hat man auch die Funktion von 20 Befehlen mal im Kopf dann muss man nur noch streng logisch denken und Regex verstehen damit man sich nicht von den vielen Sonderzeichen ablenken lässt.

für den ersten Anfang
robi
 

spoensche

Moderator
Teammitglied
Geier0815 schrieb:
@spoensche,
magst Du mir mal deinen sed-Befehl auseinander nehmen? Das ^[^global] leuchtet mir nicht wirklich ein, ebenso wenig das Fragezeichen in s(.*?)$ von dem meiner Meinung nach fehlendem slash zu schweigen, ebenso wie den fehlenden Kommas die angehängt werden sollen.

Gerne doch.

/^[^global]/: Beginnend mit irgendetwas, aber nicht mit global
(.*?): Ist weniger "gierig"

Der Part nach ^[^global] war nur so dahin geschrieben, weil es mir um die Verneinung am Anfang ging und der TE mit zwei simplen sed Befehlen nach einander das gewünschte Ergebnis gehabt hätte.
 
A

Anonymous

Gast
spoensche schrieb:
/^[^global]/: Beginnend mit irgendetwas, aber nicht mit global

Aussage ist Falsch:
hier wird alles ausgewählt was nicht mit den Buchstaben g l o b oder a anfängt ;)

robi
 
Mal ehrlich Jungs: Ihr macht mich fertig. Jedesmal wenn ich denke etwas zumindest in Grundzügen verstanden zu haben, kommt ihr mit solchen Sachen raus das ich mich fühle als wäre ich zu doof 'ne man-page zu lesen (zumindest im übertragenen Sinne). Trotzdem bin ich immer wieder begeistert was für ein Wissen hier herrscht und vor allen Dingen auch vermittelt wird. Wenn ich jetzt schon wieder sehe welche Möglichkeiten sed bereit hält, trau ich mich an awk bald gar nicht mehr ran.

@komma4,
danke für die Links, besonders der Erste wird mich sicherlich noch so manche Stunde kosten.

@robi,
kann sed auch noch Kaffee kochen? ;-)
 
A

Anonymous

Gast
Geier0815 schrieb:
kann sed auch noch Kaffee kochen? ;-)
Hab ich noch nicht probiert, wenn es mit reiner Logig möglich wäre, wer weiß ...... ;)

Aber mal so als kleine Leckbissen was man mit sed anstellen kann, wenn man nur verrückt genug ist ;) da geht mehr als nur Textdateien bearbeiten. zB:
https://github.com/aureliojargas/sed-scripts/blob/master/arkanoid.sed

SED ist durchaus eine komplette und vollständige Programmiersprache, wenn auch eine sehr eigenwillige.
Theoretisch lassen sich damit komplexe Programme schreiben, Entwicklungzeiten aber wahrscheinlich nicht in MannJahren zu errechnen sondern in Menschheitsgenerationen.

robi
 
Calvin schrieb:
  • Wenn Zeile mit "global" beginnt => füge ,, an
  • Wenn Zeile nicht mit "global" beginnt => füge , an
Hmm einfach gesagt, immer ein "," dran und bei global noch eins?
Da würde ich schreiben:
Code:
sed 's/$/,/;/^global/s/$/,/'

Als Erklärung: erster Befehl: s/$/,/ s für ersetze, dann "trenner" $ für Zeilenende, "trenner", Ersetze mit "," , "trenner"
Das ";" sorgt dafür, das der nächste Befehl folgen kann. /^global/s => Alles was mit ^global anfängt, s für ersetzen,...

Have a nice day!
 
OP
C

Calvin

Hacker
Danke, so würde es natürlich auch gehen. Mit dem Ansatz hätte ich es sogar selbst lösen können. Aber da war ich gedanklich wohl zu sehr auf meinen Ansatz versteift ;)
 
Oben