GNU recutils is een database suite op basis van platte tekst bestanden. Hiermee maak je snel toepassingen waarbij de databases zelf makkelijk door mensen te lezen en te schrijven zijn. De suite biedt functies zoals insert, update, select en delete en is geschikt voor toepassingen die verder gaan dan een simpel adresboekje.
Matto Fransen
Jose Marchesi, de ontwikkelaar van GNU recutils, ontwikkelde een database suite met als uitgangspunt dat de database bestanden zowel makkelijk door mensen te lezen (‘human readable’) als door mensen te schrijven (‘human writable’) moeten zijn. Hij kwam uit op een formaat in platte tekst, dat daardoor applicatie-onafhankelijk is, zich ook goed leent voor opname in een versiebeheersysteem en waarbij je wijzigingen makkelijk traceert met behulp van diff.
De GNU recutils suite bestaat uit een verzameling tools om te werken met platte tekst database bestanden, zogenoemde “recfiles”. GNU recutils is geschreven in C en is beschikbaar onder de open source GPL 3 licentie. GNU recutils is een volwassen suite, de 1.0 versie verscheen in 2010. Ondanks het eenvoudige formaat van recfiles zijn deze goed te parsen, automatisch te manipuleren en zijn de queries verrassend vlot. De GNU recutils suite biedt de gebruikelijke database functionaliteiten zoals insert, update, select en delete.
Recfiles formaat
Records in een recfile bestaan uit een aaneengesloten blok regels, ieder veld staat op een aparte regel. De regel is opgebouwd uit de veldnaam, een dubbele punt en spatie, gevolgd door de waarde van het veld. Een lege regel vormt de scheiding tussen twee records.
De records kunnen worden voorafgegaan door een record descriptor en aanvullende informatie zoals een declaratie van veldeigenschappen en de sorteervolgorde. Dit bestaat uit een blok van aangesloten regels die elk met een procentteken beginnen, bijvoorbeeld “%rec: boekendatabase” als record descriptor, of “%type: Jaar int” als declaratie van een veldeigenschap. Het is niet noodzakelijk alle velden te declareren. Zie listing 1 voor een voorbeeld.
Net zoals een relationele database meerdere tabellen kan bevatten, kan een recfile meerdere soorten records bevatten, iedere soort begint met zijn eigen record-descriptor en eventuele aanvullende informatie, gevolg door een lege regel gevolgd door de betreffende records. Zelf kiezen wij er overigens voor, elke tabel in een eigen recfile te plaatsen.
Queries
Met recsel vraag je eenvoudig alle records op, bijvoorbeeld ‘recsel boeken.rec’. Dit genereert een overzicht dat erg lijkt op het recfile formaat, waarbij eventuele extra lege regels en dergelijke verwijderd zijn. Recsel gebruik je ook om bepaalde records te selecteren, bijvoorbeeld recsel -e “Jaar > 2020”. Je kunt ook reguliere expressies gebruiken, bijvoorbeeld recsel -e ’Auteur~”Wells“’ boeken.rec. De optie “-i” maakt de query hoofdletter-ongevoelig.
Het is mogelijk om een gecombineerde zoekopdracht te maken, bijvoorbeeld met recsel -e ‘Auteur~“Wells” && Titel~”Sleeper”’. Let op het gebruik van de aanhalingstekens, de complete zoekopdracht achter -e staat tussen enkele aanhalingstekens, terwijl de zoekargumenten (hier: “Wells” en “Sleeper”) tussen dubbele aanhalingstekens staan.
Selecties waarbij je een datum wilt vergelijken maak je met behulp van ‘<<’ en ‘>>’.
Boeken die je gelezen hebt in de periode van januari 2018 tot en met december 2019 vraag je op met recsel -e ‘Gelezen >> “2017-12-31” && Gelezen << “2020-01-01”’ boeken.rec. Je maakt een gecombineerde zoekopdracht met de logische operatoren “&&” (and), “||” (or) en “!” (not).
Met de optie -c (count) vragen we een telling op van records die aan bepaalde criteria voldoen, bijvoorbeeld recsel -c -e ‘Auteur= “H. G. Wells”’ boeken.rec laat zien dat onze boekenlijst acht boeken van H.G. Wells bevat.
Het gebruik van de optie “-e” gevolgd door een expressie om records te selecteren kun je bij de meeste tools van de suite toepassen, zoals bij het deleten of updaten van bepaalde records. Naast selectie op basis van de waarde van bepaalde velden biedt recsel diverse andere mogelijkheden, zoals selectie van records op basis van hun positie in de recfile (bijvoorbeeld eerste vier records) en random selectie van records.
In de output van de queries die we hierboven hebben laten zien staan van alle velden van de geselecteerde records. We beperken dit met behulp van de op ‘-p’ (“print”) tot minder velden, bijvoorbeeld recsel -p ‘Titel,Auteur’ boeken.rec. De te tonen velden zet je achter elkaar, gescheiden door komma’s, zonder spaties.
Full text search
Om een full text search te doen gebruiken we de optie “quick”, bijvoorbeeld ‘recsel -i -q “london” boeken.rec’, Hiermee vinden we boeken van de auteur Jack London, maar ook het boek met de titel ‘Down and out in Paris and London’. Met grep zouden we alleen de betreffende regels krijgen, recsel toont het gehele record, of de met “-p” opgevraagde velden.
In het blok met de record definitie neem je desgewenst een regel op met de default sorteervolgorde, bijvoorbeeld ‘%sort: Titel’. Je kunt ook op de commandline een sorteervolgorde opgeven met “-s”, met een of meer velden voor het bepalen van de sorteervolgorde, zoals recsel -p ”Titel,Auteur,Gelezen” -s “Auteur,Titel” boeken.rec.
Som, gemiddelde
Met sum, max, min of avg vragen we een som, de hoogste of laatste waarde, of het gemiddelde op van een bepaald veld, bijvoorbeeld recsel -p “sum(Aantal_blz)” boeken.rec, waarbij je eventueel met de optie “-e” een selectie op de mee te tellen records aanbrengt. Met de optie “-G” groepeer je de uitkomst, zoals het aantal bladzijden per schrijver.
Rapport template
De applicatie recfmt is gemaakt om de output van recsel te parsen en deze in een gewenste opmaak te tonen. Je maakt een platte tekst bestand met de gewenste inhoud, en op die plaatsen waar je de inhoud van een bepaald veld wilt hebben, zet je de naam van het veld tussen dubbele accolades, bijvoorbeeld {{Auteur}}. Tijdens het genereren van de output worden de delen die tussen dubbele accolades staan dynamisch gevuld, de overige tekst wordt ongewijzigd overgenomen. Hiermee maak je je eigen rapportindeling.
Je gebruikt recfmt door de output van recsel er in te pipen en je geeft daarbij het template bestand op via de optie “-f”. Bijvoorbeeld recsel -e ’Auteur~”Wells”’ boeken.rec | recfmt -f mijntemplate.
Naast de letterlijke inhoud van de velden kun je tussen de accolades ook berekeningen opnemen, bijvoorbeeld {{aantal*prijs}}.
Inserten
Het platte tekst formaat van recfiles zorgt dat je makkelijk met een editor records toevoegt. Wanneer je echter met sleutels werkt, zoals een automatisch ophogende record-id, dan loop je hiermee het risico dat je een sleutel twee keer opneemt. Een betere oplossing is om een of meer automatisch updatende velden te definiëren en records toe te voegen met recins.
Bij de declaratie van veldeigenschappen wijs je met ‘%key’ een of meer velden als sleutel aan. Dit houdt in dat de dit waarde van dit veld uniek is binnen de set van records. Met behulp van ‘%auto’ wordt de waarde automatisch gevuld. Wanneer je het key-veld als integer declareert (int), dan wordt de waarde voor ieder record automatisch opgehoogd, zie ook listing 1.
Een andere zinvol automatisch gegeneerd veld is de aanmaakdatum van een record. Dit voeg je toe door een veld van het type ‘date’ te declareren en deze als ‘%auto’ te benoemen, zie listing 2. Nieuwe records krijgen dan automatisch een timestamp in dit veld.
Een record voeg je toe met recins, je neemt op de commandline het type record op (dat wat je met ‘%rec’ gedeclareerd hebt), gevolg door steeds de combinatie van “-f” gevolgd door de veldnaam en “-v” gevolg door de waarde voor dat veld. Automatisch aan te maken velden neem je hier niet in op. Je sluit de opdrachtregel af met “-t” gevolgd door de record descriptor en de naam van het databasebestand. Eventueel gebruik je een backslash (“\”) om het commando over meerdere regels te verdelen, zie listing 3.
Deleten
Je verwijdert records door middel van ‘recdel’. Met behulp van de “-e” optie selecteer je een of meer te verwijderen records. Sluit ook hier de opdrachtregel af met “-t” gevolgd door de record descriptor en de naam van het databasebestand. Dit verwijdert de betreffende records uit de recfile. Door de optie “-c” toe te voegen worden de records niet verwijderd, maar uitgecommentarieerd.
Encryptie
GNU recutils biedt de mogelijkheid om de inhoud van bepaalde velden te versleutelen. Je doet dit door de eigenschap van het veld als ‘confidential’ te declareren. Deze velden worden versleuteld opgeslagen. Het voordeel hiervan is, dat niet de hele recfile hoeft te worden versleuteld. De de uitkomst van de versleuteling wordt ACSCII-encoded in de recfile opgeslagen.
Emacs
Rec-mode is een praktische mode die beschikbaar is voor Emacs. Het bestand rec-mode.el is in het recutils tar.gz bestand opgenomen. Door deze in je Emacs configuratie op te nemen, kun je binnen Emacs de meest belangrijke functies uitvoeren. Wanneer je een recfile opent, dan blader je met de sneltoetsen ‘n’ (next) en ‘p’ (previous) door de records. Binnen een record wandel je met de tabtoets door de individuele velden van een record. De waarde van een veld wijzigen doe je met behulp van de ‘e’ (edit) toets. Wanneer het veld een datumveld is, dan wordt automatisch een kalender-buffer geopend waarmee je een datum kiest –zie screenshot 1– en met ‘m’ verwijder je spaties aan het begin en eind van de veldwaarde. Verder kun je met deze mode eenvoudig queries uitvoeren, en zijn er sneltoetsen om bijvoorbeeld het aantal records in de recfile op te vragen of een full text search te doen.
CSV importeren en exporteren
De suite bevat tools om databases te importeren en te exporteren. Voor CSV-bestanden zijn er csv2rec en rec2csv. Daarnaast importeer je MDB bestanden met mdb2rec. Wij hebben probleemloos enkele CSV-bestanden geïmporteerd, belangrijk hierbij is dat spaties in de veldnamen niet zijn toegestaan en dat csv2rec ervan uitgaat dat je een komma als scheidingsteken gebruikt en niet een puntkomma.
Het leek ons wel leuk met een wat grotere recordset te testen, en maakten een recfile met 7.500 records van ieder 13 velden, dit levert een bestand op met 105.000 regels. Met een sortering op drie verschillende velden duurt een recsel-query 0.6 seconden, met andere woorden ook bij grotere aantallen records blijft het allemaal prima werkbaar. De installatie van recutils doe je op de bekende Linux distributies en op FreeBSD eenvoudig met behulp van de bijbehorende package manager. Op OpenBSD download je het tar.gz bestand van de laatste versie, de installatie verloopt vlotjes met het bekende trio ./configure, make en make install.
De suite biedt meer dan we hier kunnen laten zien. Met behulp van foreign keys voer je bijvoorbeeld joined queries uit op meerdere tabellen en met remote descriptors sla je de database gedistribueerd op. De GNU recutils suite biedt een handige en robuuste oplossing voor die gevallen waarin geavanceerde database systemen zoals MySQL of PostgreSQL overkill zijn. Het hoeft echter niet alleen bij oplossingen voor kleinschalige oplossingen met hooguit een paar honderd records te blijven. Linux-systemen en de verschillende BSD-systemen bevatten van oudsher een ruime verzameling krachtige tools rondom het werken met platte tekst. GNU recutls past uitstekend in deze traditie, waardoor je al snel via scripts je recfiles gaat opbouwen of aanpassen, of de output van recsel verder verwerkt middels andere scripts, bijvoorbeeld om mooie rapporten te maken via LaTeX of groff. Met de GNU recutils suite verbind je zo nut en noodzaak met fijn, lekker scripten.