Toon posts:

[SED] Pattern space -> holspace -> substitueren

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hallo allemaal,

Weet iemand toevallig hie je de pattern space kunt kopieren naar de hold space en deze hiernaa (bv bij een volgende regel) kunt substitueren voor of achter de huidige pattern space?

Ik zit hier wel wat te proberen maar kom er niet aan uit. Een voorbeeldje van een bestand waar ik het sed commando op los laat:

0deze regel begint met een cijfer
Adeze regel begint met een letter
Bdeze regel begint met een letter

Nu wil dus dit bestand dmv het cat commando aan het sed commando voeren. Hierbij moet als de regel met een cijfer begint (dus [0-9]) worden gekopieerd naar de hold space. Als de volgende regel met een letter begint, moet de inhoud van de hold space vóór de regel worden gesubstitueerd. VB van de output:

0deze regel begint met een cijferAdeze regel begint met een letter
0deze regel begint met een cijferBdeze regel begint met een letter

Verwijderd

Wat is een hold space? Als het iets complexer wordt, dan doe ik het in perl. Dat is makkelijker te schrijven, te volgen en te debuggen, dan cryptische shell commando's. En als ik het scriptje dan over een jaar terugzie, kan ik er nog wat mee, laat staan iemand anders.

Verwijderd

Topicstarter
Verwijderd schreef op 19 juli 2004 @ 11:13:
Wat is een hold space? Als het iets complexer wordt, dan doe ik het in perl. Dat is makkelijker te schrijven, te volgen en te debuggen, dan cryptische shell commando's. En als ik het scriptje dan over een jaar terugzie, kan ik er nog wat mee, laat staan iemand anders.
Het is niet de bedoeling het scriptje in perl te maken, moet in de shell.

Pattern space: de regel die in de buffer staat om bewerkt te worden, deze verandert dus steeds.

Hold space: deze buffer is initieel leeg maar KAN worden gevuld met data. De vraag is dus hoe.

  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

Dit staat gewoon in de man page?

code:
1
2
3
       h H    Copy/append pattern space to hold space.

       g G    Copy/append hold space to pattern space.

All my posts are provided as-is. They come with NO WARRANTY at all.


Verwijderd

Topicstarter
CyBeR schreef op 19 juli 2004 @ 11:29:
Dit staat gewoon in de man page?

code:
1
2
3
       h H    Copy/append pattern space to hold space.

       g G    Copy/append hold space to pattern space.
Dit is inderdaad al iets waar ik iets mee kan, weet iemand hoe ik dit kan toepassen in een sed commando, dit maak ik niet op uit de man of deze reactie.

  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

Dat staat in 'info sed' :) de manpage is bij sed slechts bedoeld als geheugensteuntje voor mensen die sed kennen. De info page is een volledige uitleg.

All my posts are provided as-is. They come with NO WARRANTY at all.


Verwijderd

Topicstarter
CyBeR schreef op 19 juli 2004 @ 12:05:
Dat staat in 'info sed' :) de manpage is bij sed slechts bedoeld als geheugensteuntje voor mensen die sed kennen. De info page is een volledige uitleg.
Misschien dat er nog iemand een voorbeeldje heeft , dit ter verduidelijking

  • blaataaps
  • Registratie: Juli 2001
  • Niet online
Verwijderd schreef op 19 juli 2004 @ 12:17:
[...]


Misschien dat er nog iemand een voorbeeldje heeft , dit ter verduidelijking
Misschien moet je nu even die info-page doorlezen ipv alles hier vragen.

Verwijderd

Topicstarter
blaataaps schreef op 19 juli 2004 @ 12:18:
[...]

Misschien moet je nu even die info-page doorlezen ipv alles hier vragen.
Misschien dat blaataaps niet meteen in de aanval moet gaan als er om een voorbeeldje wordt gevraagd ;) , uiteraard lees ik de info page door.

  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

In de info page staan voorbeelden ;)

All my posts are provided as-is. They come with NO WARRANTY at all.


  • Wilke
  • Registratie: December 2000
  • Laatst online: 10:41
Misschien dat het toch handiger is om naar het advies van liquidos te luisteren, sed is zeker niet de makkelijkste manier om dit te doen - als het er al mee lukt; ik vraag me af of knippen/plakken tussen verschillende regels met sed gaat werken.

Verwijderd

Verwijderd schreef op 19 juli 2004 @ 10:26:
Ik zit hier wel wat te proberen maar kom er niet aan uit. Een voorbeeldje van een bestand waar ik het sed commando op los laat:

0deze regel begint met een cijfer
Adeze regel begint met een letter
Bdeze regel begint met een letter

VB van de output:

0deze regel begint met een cijferAdeze regel begint met een letter
0deze regel begint met een cijferBdeze regel begint met een letter
Dit is vrij gemakkelijk, zie hier het script:
code:
1
2
3
4
5
6
7
8
/^[0-9]/{
        h
        d
}
/^[A-Za-z]/{
        G
        s/\(.*\)\n\(.*\)/\2\1/
}


Het eerste zegt: Als de regel met een cijfer begint, dan bewaren we die (h), en dan wordt deze verwijderd (d), aangezien je die niet in de uitvoer wilt zien.

Daarna komt, als de regel met een letter begint, dan plakken we de holdspace achter de pattern space (G). Dan staan ze echter verkeerd om, maar aangezien ze worden gescheiden door een newline (vanwege de G), kunnen ze eenvoudigweg gesubstitueerd worden.

In AWK kan het ook vrij gemakkelijk:
code:
1
2
3
4
5
6
/^[0-9]/ {
        s=$0
}
/^[A-Za-z]/ {
        print s $0
}


Beide scripts kun je of in een bestand stoppen, en dan via -f dat bestand opgeven, of achter elkaar op de command line proppen, bij sed moet je dan wel de commando's door ; scheiden. /^[0-9]/{h;d} dus.

Als je een beetje sed kunt is 't over een jaar nog wel te snappen, zeker als je er met # wat commentaar bij zet.

Verwijderd

Topicstarter
Ik heb nog eens even zitten proberen en heb nu het volgende gedaan:

Ik heb de volgende file die ik cat:
code:
1
2
3
4
0 deze regel bevat de directorynaam

a_filename_nummer_een
b_filename_nummer_twee


Ik gebruik het volgende commando:

code:
1
2
cat testfile | sed -e "s/^[a-z].*$/hier moet de holdspace komen plus de pattern space/" 
-e "s/^[0-9].*$/hier moet de pattern space komen/"


Dit geeft het volgende resultaat:

code:
1
2
3
4
hier moet de pattern space komen

hier moet de holdspace komen plus de pattern space
hier moet de holdspace komen plus de pattern space


Onderscheid maken gaat goed, nu kun je dus nog met -e "h" de pattern space kopieren naar de holdspace, nu is het enige dus wat nog moet gaan werken dat de inhoud van de holdspace, wordt gebruikt bij het substutieren ipv de gebruikte tekst.

Verwijderd

Verwijderd schreef op 19 juli 2004 @ 13:12:
Onderscheid maken gaat goed, nu kun je dus nog met -e "h" de pattern space kopieren naar de holdspace, nu is het enige dus wat nog moet gaan werken dat de inhoud van de holdspace, wordt gebruikt bij het substutieren ipv de gebruikte tekst.
Zo werkt het niet. Sed voert voor elke regel van de invoer alle regels in het script uit. Normaliter is je script een heel simpel iets, bijvoorbeeld alleen 's/blaet/mecker/'.

Echter, wat er gebeurt is dat een regel wordt ingelezen, in de zogenaamde pattern space, en dat je daar commando's op los laat. Als dan alles klaar is, dan wordt de pattern space afgedrukt (tenzij je sed -n doet).

Om te beslissen of een regel wordt uitgevoerd kun je criteria opgeven in sed, namelijk in de vorm van getallen, of in de vorm van patronen. Stel, je wilt alles behalve de eerste 4 regels afdrukken, dan zeg je '1,4d' dan worden alleen de eerste vier regels verwijderd, voor de rest van de regels geldt het patroon niet meer.

Een ander patroon is een reguliere expressie, die je tussen // zet, bijvoorbeeld /^[0-9]/d, dit verwijdert alle regels die met een cijfer beginnen, andere regels laat het ongemoeid. Zoiets zie je dus ook in bovenstaand script van mij.

Zoals gezegd is er ook een hold space in sed, naast de pattern space, daar kun je dus regels (tijdelijk) instoppen. Als je dan een ander patroon voorbij ziet komen in de pattern space, dan haal je die regel weer uit de hold space, en dan zorg je dat die op die manier in de pattern space komt zoals jij wilt, waarna sed (zoals gebruikelijk) weer de pattern space uitprint.

De commando's voor de pattern space en de hold space kun je in de man page vinden. Nog een voorbeeld, wat je bijvoorbeeld met sed kunt doen:
cat <bestand> | sed -n '$p;$!{h;n;p;g;p;}'

Dit wisselt opeenvolgende regels om (behalve de laatste regel bij een bestand met een oneven aantal regels). $ is een shortcut voor 'laatste regel', die wordt simpel weg afgedrukt. Het ding daarna: $! zegt dat het komende commando voor alle regels geldt die niet de laatste regel zijn, met { } kun je dus een blok maken. De huidige regel wordt bewaard (met h), de n leest een volgende regel in (omdat we -n opgeven print het de oude niet), print die regel direct (p), dan halen we de oude regel weer op (g), en printen die erna.

Kortom, regel 2 komt voor 1, 3 komt voor 4, 5 voor 6, etc. Voor een groot ovezicht aan sed-scripts en wat je er allemaal mee kunt (maar of je het wilt) kun je op http://sed.sf.net kijken.

Verwijderd

Topicstarter
Verwijderd schreef op 19 juli 2004 @ 13:33:
[...]


Zo werkt het niet. Sed voert voor elke regel van de invoer alle regels in het script uit. Normaliter is je script een heel simpel iets, bijvoorbeeld alleen 's/blaet/mecker/'.

Echter, wat er gebeurt is dat een regel wordt ingelezen, in de zogenaamde pattern space, en dat je daar commando's op los laat. Als dan alles klaar is, dan wordt de pattern space afgedrukt (tenzij je sed -n doet).

Om te beslissen of een regel wordt uitgevoerd kun je criteria opgeven in sed, namelijk in de vorm van getallen, of in de vorm van patronen. Stel, je wilt alles behalve de eerste 4 regels afdrukken, dan zeg je '1,4d' dan worden alleen de eerste vier regels verwijderd, voor de rest van de regels geldt het patroon niet meer.

Een ander patroon is een reguliere expressie, die je tussen // zet, bijvoorbeeld /^[0-9]/d, dit verwijdert alle regels die met een cijfer beginnen, andere regels laat het ongemoeid. Zoiets zie je dus ook in bovenstaand script van mij.

Zoals gezegd is er ook een hold space in sed, naast de pattern space, daar kun je dus regels (tijdelijk) instoppen. Als je dan een ander patroon voorbij ziet komen in de pattern space, dan haal je die regel weer uit de hold space, en dan zorg je dat die op die manier in de pattern space komt zoals jij wilt, waarna sed (zoals gebruikelijk) weer de pattern space uitprint.

De commando's voor de pattern space en de hold space kun je in de man page vinden. Nog een voorbeeld, wat je bijvoorbeeld met sed kunt doen:
cat <bestand> | sed -n '$p;$!{h;n;p;g;p;}'

Dit wisselt opeenvolgende regels om (behalve de laatste regel bij een bestand met een oneven aantal regels). $ is een shortcut voor 'laatste regel', die wordt simpel weg afgedrukt. Het ding daarna: $! zegt dat het komende commando voor alle regels geldt die niet de laatste regel zijn, met { } kun je dus een blok maken. De huidige regel wordt bewaard (met h), de n leest een volgende regel in (omdat we -n opgeven print het de oude niet), print die regel direct (p), dan halen we de oude regel weer op (g), en printen die erna.

Kortom, regel 2 komt voor 1, 3 komt voor 4, 5 voor 6, etc. Voor een groot ovezicht aan sed-scripts en wat je er allemaal mee kunt (maar of je het wilt) kun je op http://sed.sf.net kijken.
Bedankt voor de zeer heldere uitleg, hier moet het inderdaad mee lukken!

Verwijderd

Ik weet dat je geen perl wil, het script doet ook vast niet precies wat je wil, maar dees had ik nog ff gemaakt, om me perl skills een beetje bij te houden. Het kan vast simpeler, maar dit is hopelijk redelijk leesbaar.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
$ cat joinifnumber 
#!/usr/bin/perl
#Mon Jul 19 13:04:53 CEST 2004, start
# adds the second line if the previous starts with a number

$debug=0;
$data_file= $ARGV[0];
$oldline="";

open(INPUT, $data_file) || die("Could not open file $data_file!");
while (<INPUT>) 
{
  $line = $_;
  if ( $line =~ m/^\d/ )  # starts with number
  {
    chomp $line;  # remove CR
    if (  ($oldline != "") ) { # not empty
      print "$oldline\n"; 
    }
    $oldline=$line;
    print "DEBUG: OLD=$oldline, LINE=$line\n" if $debug;
  }
  else
  {
    print "$oldline$line"; 
    $oldline="";
  }
}
close (INPUT);

if ( $oldline != "" ) { 
  print "$oldline\n";
}

$ cat lines 
1regel1
Aregel2
3regel3
Bregel4
5regel5
6regel6
Cregel7
Dregel8
9regel9
$ ./joinifnumber lines 
1regel1Aregel2
3regel3Bregel4
5regel5
6regel6Cregel7
Dregel8
9regel9

Verwijderd

Verwijderd schreef op 19 juli 2004 @ 13:59:

$ ./joinifnumber lines
1regel1Aregel2
3regel3Bregel4
5regel5
6regel6Cregel7
Dregel8
9regel9
[/code]
Zoals ik z'n probleem begreep moest de uitvoer zijn:
code:
1
2
3
4
1regel1Aregel2
3regel3Bregel4
6regel6Cregel7
6regel6Dregel8


Wat in Perl ook zo kan:
code:
1
2
3
4
#!/usr/bin/perl -n
chomp;
$s=$_ if /^[0-9]/;
print "$s$_\n" if /^[A-Za-z]/
Pagina: 1