[Unix] Elke 100.000 regels een regel invoegen

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • One_Gandalf
  • Registratie: April 2002
  • Laatst online: 10:08
Ik heb een file die bestaat uit ongeveer 5 miljoen regels met een maximale lengte van ongeveer 4.000 tekens.

Nu wil ik om de 100.000 regels een tekstregel invoegen.

Hoe kan ik dit het beste doen?

Ik heb het met 'awk' geprobeerd echter 'awk' klaagt over de lengte van de regels. Mijn versie van 'awk' kan slechts een maximale regellengte van 3.000 tekens aan.

Ik dacht zelf aan 'sed' als alternatief maar kom hier niet uit omdat ik te weinig weet van 'sed'.

Het 'awk-script' ziet er als volgt uit :

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
nawk '

BEGIN  {
           teller = 0
           FS = ";"
       }

       {
           teller = teller + 1
           print $0
           if ( teller == 100000 )
           {
               print "in te voegen regel"
               teller = 0
           }
       }' < bron > doel

[ Voor 32% gewijzigd door One_Gandalf op 05-08-2010 15:47 ]


Acties:
  • 0 Henk 'm!

  • sparks
  • Registratie: December 2002
  • Laatst online: 09:30
paar regels c kloppen is misschien nog wel eenvoudiger.

Acties:
  • 0 Henk 'm!

  • One_Gandalf
  • Registratie: April 2002
  • Laatst online: 10:08
sparks schreef op donderdag 05 augustus 2010 @ 15:09:
paar regels c kloppen is misschien nog wel eenvoudiger.
Ja, daar had ik ook aan gedacht echter ik ben niet zo'n ster met 'C'. En het zou toch met de standaard tools binnen Unix mogelijk moeten zijn om dit voor elkaar te krijgen?

Acties:
  • 0 Henk 'm!

  • u_nix_we_all
  • Registratie: Augustus 2002
  • Niet online
Met "split" opdelen in blokken van 100.000 regels:
code:
1
split -l 100000 <bestand>

Dan krijg je een rijtje bestanden bestand.000 , bestand.001 etc.
( edit: ff gechecked, zal eerder bestand.xaa , bestand.xab etc zijn)

Dan samenvoegen met extra regels:
code:
1
2
3
4
5
for i in `ls bestand.*`
do
cat $i  >> outfile
echo >> outfile
done


(Dit is ff uit m'n hoofd, zorg er wel voor dat de wildcard alleen de gesplitte parts oppakt)

[ Voor 8% gewijzigd door u_nix_we_all op 05-08-2010 15:20 ]

You don't need a parachute to go skydiving. You need a parachute to go skydiving twice.


Acties:
  • 0 Henk 'm!

  • sfranken
  • Registratie: Mei 2010
  • Laatst online: 01-10 14:47
Toevallig was ik hier ook naar op zoek, en jouw oplossing werkt als een trein u_nix. Dankje!

Acties:
  • 0 Henk 'm!

  • One_Gandalf
  • Registratie: April 2002
  • Laatst online: 10:08
u_nix_we_all schreef op donderdag 05 augustus 2010 @ 15:15:
Met "split" opdelen in blokken van 100.000 regels:
code:
1
split -l 100000 <bestand>

Dan krijg je een rijtje bestanden bestand.000 , bestand.001 etc.

Dan samenvoegen met extra regels:
code:
1
2
3
4
5
for i in `ls bestand.*`
do
cat $i  >> outfile
echo >> outfile
done


(Dit is ff uit m'n hoofd, zorg er wel voor dat de wildcard alleen de gesplitte parts oppakt)
Bedankt dit is precies waar ik naar op zoek was. Stom dat ik zelf niet op het split-commando was gekomen. En nu nog kijken of het goed gaat ;)

Acties:
  • 0 Henk 'm!

  • u_nix_we_all
  • Registratie: Augustus 2002
  • Niet online
One_Gandalf schreef op donderdag 05 augustus 2010 @ 15:21:
[...]


Bedankt dit is precies waar ik naar op zoek was. Stom dat ik zelf niet op het split-commando was gekomen. En nu nog kijken of het goed gaat ;)
Ja, ben benieuwd of dit ook voor zulke grote files goed gaat. In theorie moet het werken ;-)

You don't need a parachute to go skydiving. You need a parachute to go skydiving twice.


Acties:
  • 0 Henk 'm!

  • One_Gandalf
  • Registratie: April 2002
  • Laatst online: 10:08
u_nix_we_all schreef op donderdag 05 augustus 2010 @ 15:28:
Ja, ben benieuwd of dit ook voor zulke grote files goed gaat. In theorie moet het werken ;-)
Werkt als een speer.

De doorlooptijd was slechts 3 minuten en 14 seconden.

:)

[ Voor 3% gewijzigd door One_Gandalf op 05-08-2010 16:14 ]


Acties:
  • 0 Henk 'm!

  • One_Gandalf
  • Registratie: April 2002
  • Laatst online: 10:08
u_nix_we_all schreef op donderdag 05 augustus 2010 @ 15:15:
Dan samenvoegen met extra regels:
code:
1
2
3
4
5
for i in `ls bestand.*`
do
cat $i  >> outfile
echo >> outfile
done
Om de schijf niet helemaal vol te laten lopen heb ik de volgende optimalisatie toegevoegd op regel 4 :

code:
1
2
3
4
5
6
for i in `ls bestand.*`
do
  cat $i  >> outfile
  rm -f $i
  echo >> outfile
done

Acties:
  • 0 Henk 'm!

  • One_Gandalf
  • Registratie: April 2002
  • Laatst online: 10:08
u_nix_we_all schreef op donderdag 05 augustus 2010 @ 15:15:
( edit: ff gechecked, zal eerder bestand.xaa , bestand.xab etc zijn)
Standaard worden bestanden met de naam 'xaa', 'xab' enz. aangemaakt.

Ik heb dit opgelost door ook een prefix op te geven als laatste parameter bij het split-commando :

code:
1
split -l 100000 bestand prefix


Als de prefix gelijk is aan de bestandsnaam dan zal de for-loop ook het originele bestand meenemen waar je al voor waarschuwde.
RemcoDelft schreef op donderdag 05 augustus 2010 @ 17:20:
Is dit een klassieke Unix of gewoon een Tux-kloon (met veel meer commando's)?
Het is een klassieke Unix (Tru64/OSF1/Alpha).

[ Voor 18% gewijzigd door One_Gandalf op 06-08-2010 11:27 ]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Zou je even je postgedrag (triple post) in de gaten willen houden voortaan ;) Gebruik de edit knop ( Afbeeldingslocatie: http://tweakimg.net/g/forum/images/icons/edit.gif ) als je iets toe te voegen hebt; je topic herhaaldelijk omhoogschoppen is niet nodig en die waarschuwing staat er ook niet voor jan-joker ;)

[ Voor 19% gewijzigd door RobIII op 05-08-2010 17:16 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • RemcoDelft
  • Registratie: April 2002
  • Laatst online: 03-05 10:30
Is dit een klassieke Unix of gewoon een Tux-kloon (met veel meer commando's)?
u_nix_we_all schreef op donderdag 05 augustus 2010 @ 15:28:
[...]

Ja, ben benieuwd of dit ook voor zulke grote files goed gaat. In theorie moet het werken ;-)
Ik heb lang geleden al vele gigabyes door split geduwd, zonder problemen.

Wellicht kan je in de toekomst ook "tail" en "head" gebruiken, fantastische commando's om even snel een bepaald deel van een file te pakken te krijgen.

Acties:
  • 0 Henk 'm!

  • u_nix_we_all
  • Registratie: Augustus 2002
  • Niet online
RemcoDelft schreef op donderdag 05 augustus 2010 @ 17:20:

Wellicht kan je in de toekomst ook "tail" en "head" gebruiken, fantastische commando's om even snel een bepaald deel van een file te pakken te krijgen.
Die kunnen ook handig zijn idd. Maar vaak was dat dan in combinatie met een pipe naar een ander tooltje, en dat is iets waar je bij zulke grote files erg mee moet oppassen, de buffer daarvoor kan dan vollopen.

You don't need a parachute to go skydiving. You need a parachute to go skydiving twice.


Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

u_nix_we_all schreef op donderdag 05 augustus 2010 @ 17:38:
[...]
Die kunnen ook handig zijn idd. Maar vaak was dat dan in combinatie met een pipe naar een ander tooltje, en dat is iets waar je bij zulke grote files erg mee moet oppassen, de buffer daarvoor kan dan vollopen.
pipes hebben in de kernel standaard 16Kb buffer en zijn blocking... Als ie volloopt blockt het sending process tot het receiving end de boel weer verder uitleest...

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 02:18
Misschien mosterd na de maaltijd, maar volgens mij kan dit extreem eenvoudig met sed:
sed '0~10000 a XXX'

Waarbij XXX natuurlijk de in te voegen regel is. Met 0~x geef je elke x regels een commando uitgevoerd moet worden (beginnend bij 0; de eerste regel is regel 1) en a staat voor append.

Dit is natuurlijk wel onder de aanname dat sed niet ook vervelende interne limieten heeft, maar GNU sed zou in ieder geval niet gelimiteerd moeten zijn. De POSIX standaard eist minimaal support voor regels van 8KB, maar er kunnen heel goed niet-standaard-compliant implementaties bestaan.

edit:
Trouwens, in NOS hadden ze je dit waarschijnlijk ook wel kunnen vertellen. Dat is sowieso meer de place to be voor vragen over het gebruik van UNIX/POSIX command line tools. PRG gaat meer om het zelf programmeren (vandaar ook sparks' reactie ;)) en hoewel awk/sed scripten natuurlijk ook borderline programmeren is, kunnen ze je daar meestal wel op een simpele oplossingen wijzen.

[ Voor 57% gewijzigd door Soultaker op 07-08-2010 16:00 ]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
^^ Met hem.
PRG >> NOS

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

u_nix_we_all schreef op donderdag 05 augustus 2010 @ 15:15:
Met "split" opdelen in blokken van 100.000 regels:
code:
1
split -l 100000 <bestand>

Dan krijg je een rijtje bestanden bestand.000 , bestand.001 etc.
( edit: ff gechecked, zal eerder bestand.xaa , bestand.xab etc zijn)

Dan samenvoegen met extra regels:
code:
1
2
3
4
5
for i in `ls bestand.*`
do
cat $i  >> outfile
echo >> outfile
done


(Dit is ff uit m'n hoofd, zorg er wel voor dat de wildcard alleen de gesplitte parts oppakt)
code:
1
for i in *.bla; do iets; done


is iets beter.

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


Acties:
  • 0 Henk 'm!

  • sam.vimes
  • Registratie: Januari 2007
  • Laatst online: 08-06 08:44
One_Gandalf schreef op donderdag 05 augustus 2010 @ 16:04:
[...]
De doorlooptijd was slechts 3 minuten en 14 seconden.
:)
Dat is knap veel voor maar een paar miljoen regels.
Ik denk dat je sneller en eenvoudiger klaar bent bent met Perl:
code:
1
perl -wne 'print; $. % 100_000 == 0 and print "tussen te voegen tekst\n"' inputfile > outputfile

Kost ook minder tussentijdse opslagruimte van al die gesplitte files, die je dus ook niet hoeft op te ruimen.
Als je de inputfile "in place" wilt editen (dus als je na afloop een mv outputfile inputfile gaat uitvoeren), is de -i-optie van Perl handig:
code:
1
perl -i -wne 'print; $. % 100_000 == 0 and print "tussen te voegen tekst\n"' inputfile
Pagina: 1