------------------------------------------------------------------------- HANDIGE EEN-REGELIGE SCRIPTS VOOR SED (Unix stream editor) Dec. 29, 2005 Samengesteld door Eric Pement - pemente[at]northpark[dot]edu version 5.5 Vertaald door Harm Ensing - harm.ensing[at]atosorigin[dot]com De meest recente versie van dit bestand (in het Engels) is meestal te vinden op: http://underpop.online.fr/s/sed/sed1line.txt http://www.pement.org/sed/sed1line.txt Daarnaast is het beschikbaar in de volgende talen: Chinees - http://underpop.online.fr/s/sed/sed1line_zh-cn.html Czech - http://underpop.online.fr/s/sed/sed1line_cz.html Nederlands - http://underpop.online.fr/s/sed/sed1line_nl.html Frans - http://underpop.online.fr/s/sed/sed1line_fr.html Duits - http://underpop.online.fr/s/sed/sed1line_de.html Portugees - http://underpop.online.fr/s/sed/sed1line_pt-br.html REGELAFSTAND: # alle regels scheiden door een lege regel sed G # In een bestand dat al lege regels bevat alle regels scheiden door # een lege regel. Het resultaat mag niet meer dan een lege regel # tussen de tekstregels bevatten. sed '/^$/d;G' # tekstregels scheiden door twee lege regels. sed 'G;G' # lege regels verwijderen, er vanuit gaande dat de even genummerde # regels de lege regels zijn. sed 'n;d' # een regel invoegen boven iedere regel die voldoet aan "regex" sed '/regex/{x;p;x;}' # een regel invoegen onder iedere regel die voldoet aan "regex" sed '/regex/G' # een regel invoegen boven en onder iedere regel die voldoet aan "regex" sed '/regex/{x;p;x;G;}' NUMMERING: # nummer iedere regel eenvoudig links aansluitend # Gebruik van tab (zie opmerking over '\t' aan het eind van dit bestand) # in plaats van spatie houdt de marge in stand. sed = filename | sed 'N;s/\n/\t/' # nummer iedere regel, nummer aan linkerkant en rechts-aansluitend sed = filename | sed 'N; s/^/ /; s/ *\(.\{6,\}\)\n/\1 /' # nummer iedere regel, maar alleen als regel niet leeg is sed '/./=' filename | sed '/./N; s/\n/ /' # tel het aantal regels (emuleert unix commando "wc -l") sed -n '$=' TEKST CONVERSIE EN VERVANGING: # IN UNIX OMGEVING: vervang DOS regeleinde (CR/LF) door Unix formaat. sed 's/.$//' # er vanuit gaande dat alle regels eindigen met CR/LF sed 's/^M$//' # in bash/tcsh, druk achtereenvolgens op Ctrl-V en Ctrl-M sed 's/\x0D$//' # werkt in ssed en gsed versie 3.02.80 of hoger # IN UNIX OMGEVING: vervang Unix regeleinde (LF) door DOS formaat. sed "s/$/`echo -e \\\r`/" # commando regel onder ksh sed 's/$'"/`echo \\\r`/" # commando regel onder bash sed "s/$/`echo \\\r`/" # commando regel onder zsh sed 's/$/\r/' # gsed versie 3.02.80 of hoger # IN DOS OMGEVING: vervang Unix regeleinde (LF) door DOS formaat. sed "s/$//" # methode een sed -n p # methode twee # IN DOS OMGEVING: vervang DOS regeleinde (CR/LF) door Unix formaat. # Dit kan alleen met UnxUtils sed versie 4.0.7 of hoger. Het UnxUtils # versienummer kan worden opgeroepen met de "--text" switch die # verschijnt als de "--help" switch gebruikt wordt. Een andere methode # om met sed DOS regeleinden te vervangen door Unix regeleinden in een # DOS omgeving is er niet. Gebruik hiervoor het "tr" commando. sed "s/\r//" infile >outfile # UnxUtils sed versie 4.0.7 of hoger tr -d \r <infile >outfile # GNU tr versie 1.22 of hoger # verwijder voorafgaande witruimte (spatie en tab) van het begin van # iedere regel. Dit zorgt voor uitlijning van de tekst aan de linkerkant. sed 's/^[ \t]*//' # zie opmerking over '\t' aan het eind. # verwijder afsluitende witruimte (spatie en tab) van het einde # van iedere regel. sed 's/[ \t]*$//' # zie opmerking over '\t' aan het eind van dit bestand. # verwijder zowel voorafgaande als afsluitende witruimte van ieder regel. sed 's/^[ \t]*//;s/[ \t]*$//' # voeg vijf spaties in aan het begin van iedere regel. sed 's/^/ /' # sluit alle tekst rechts aan op een breedte van 79 kolommen. sed -e :a -e 's/^.\{1,78\}$/ &/;ta' # stel in op 78 plus 1 spaties # Centreer tekst op een breedte van 79 kolommen. In methode een # worden spaties aan het begin van een regel meegerekend en worden # afsluitende spaties toegevoegd aan het einde van de regel. # In methode twee worden voorafgaande spaties niet meegenomen en wordt # de regel aan het einde niet aangevuld met spaties. sed -e :a -e 's/^.\{1,77\}$/ & /;ta' # methode een sed -e :a -e 's/^.\{1,77\}$/ &/;ta' -e 's/\( *\)\1/\1/' # methode twee # zoek en vervang "foo" door "bar" op ieder regel. sed 's/foo/bar/' # vervangt iedere eerste "foo" op een regel sed 's/foo/bar/4' # vervangt aleen iedere vierde "foo" sed 's/foo/bar/g' # vervangt iedere "foo" in een regel sed 's/\(.*\)foo\(.*foo\)/\1bar\2/' # vervangt de op-een-na-laatste sed 's/\(.*\)foo/\1bar/' # vervangt alleen de laatste "foo" # vervang "foo" door "bar", maar alleen op regels die "baz" bevatten. sed '/baz/s/foo/bar/g' # vervang "foo" door "bar", maar NIET op regels die "baz" bevatten. sed '/baz/!s/foo/bar/g' # vervang "scarlet" of "ruby" of "puce" door "red". gsed 's/scarlet\|ruby\|puce/red/g' # alleen GNU sed sed 's/scarlet/red/g;s/ruby/red/g;s/puce/red/g' # meeste seds # print regels in omgekeerde volgorde (emuleert "tac"). # NB: door een bug in HHsed v1.5 worden lege regels verwijderd. sed '1!G;h;$!d' # methode een sed -n '1!G;h;$p' # methode twee # print karakters op een regel in omgekeerde volgorde (emuleert "tac"). sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//' # voeg regels twee-aan-twee samen (zoals commando "paste" doet). sed '$!N;s/\n/ /' # als een regel eindigt met een backslash (\), voeg dan de volgende # regel er aan toe. sed -e :a -e '/\\$/N; s/\\\n//; ta' # als een regel begint met het gelijk-teken, voeg het dan toe aan de # voorgaande regel en vervang "=" door een spatie. sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D' # voeg komma's toe aan getallen, vervangt "1234567" door "1,234,567". gsed ':a;s/\B[0-9]\{3\}\>/,&/;ta' # GNU sed sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta' # andere seds # voeg komma's toe aan getallen met decimale punt en minteken (GNU sed). gsed -r ':a;s/(^|[^0-9.])([0-9]+)([0-9]{3})/\1\2,\3/g;ta' # voeg een lege regel in na iedere vijfde regel (na regel 5, 10, 15 ...) gsed '0~5G' # alleen GNU sed sed 'n;n;n;n;G;' # andere seds SELECTIEF PRINTEN VAN BEPAALDE REGELS: # print de eerste tien regels van een bestand (emuleert "head"). sed 10q # print de eerste regel van een bestand (emuleert "head -1"). sed q # print de laatste tien regels van een bestand (emuleert "tail"). sed -e :a -e '$q;N;11,$D;ba' # print de laatste twee regels van een bestand (emuleert "tail -2"). sed '$!N;$!D' # print de laatste regel van een bestand (emuleert "tail -1"). sed '$!d' # methode een sed -n '$p' # methode twee # print de op-een-na-laatste regel van een bestand. sed -e '$!{h;d;}' -e x # bij een-regelig bestand, print lege regel sed -e '1{$q;}' -e '$!{h;d;}' -e x # bij een-regelig bestand, print die regel sed -e '1{$d;}' -e '$!{h;d;}' -e x # bij een-regelig bestand, print niets # print enkel de regels die overeen komen met een reguliere expressie # (emuleert "grep") sed -n '/regexp/p' # methode een sed '/regexp/!d' # methode twee # print enkel de regels die NIET overeen komen met een reguliere expressie # (emuleert "grep -v") sed -n '/regexp/!p' # methode een, correspondeert met voorgaande sed '/regexp/d' # methode twee, eenvoudigere syntax # print de regel onmiddelijk voor een regexp, maar niet de regel # die de regexp bevat. sed -n '/regexp/{g;1!p;};h' # print de regel onmiddelijk na een regexp, maar niet de regel # die de regexp bevat. sed -n '/regexp/{n;p;}' # print een enkele regel voor en na regexp, met het regelnummer # waarop regexp voorkomt (identiek aan "grep -A1 -B1"). sed -n -e '/regexp/{=;x;1!p;g;$!N;p;D;}' -e h # zoek naar regels die zowel AAA als BBB als CCC bevatten # (in willekeurige volgorde). sed '/AAA/!d; /BBB/!d; /CCC/!d' # zoek naar regels die zowel AAA als BBB als CCC bevatten # (in die volgorde). sed '/AAA.*BBB.*CCC/!d' # zoek naar regels die AAA of BBB of CCC bevatten (emuleert "egrep"). sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d # meeste seds gsed '/AAA\|BBB\|CCC/!d' # alleen GNU sed # print een paragraaf als het AAA bevat # (paragrafen gescheiden door lege regels) # Bij gebruik van HHsed v1.5 moet in de volgende drie scripts # 'x;' worden gevolgd door 'G;'. sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;' # print paragraaf als het AAA en BBB en CCC bevat # (in willekeurige volgorde). sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;/BBB/!d;/CCC/!d' # print paragraaf als het AAA of BBB of CCC bevat. sed -e '/./{H;$!d;}' -e 'x;/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d gsed '/./{H;$!d;};x;/AAA\|BBB\|CCC/b;d' # alleen GNU sed # print alleen regels die 65 of meer karakters bevatten. sed -n '/^.\{65\}/p' # print alleen regels die minder dan 65 karakters bevatten. sed -n '/^.\{65\}/!p' # methode een, komt overeen met bovenstaande sed '/^.\{65\}/d' # methode twee, eenvoudigere syntax # print vanaf de regel waarop regex voorkomt tot einde bestand. sed -n '/regexp/,$p' # print deel van bestand gebaseerd op regelnummers (regel 8-12, inclusief). sed -n '8,12p' # methode een sed '8,12!d' # methode twee # print regel nummer 52. sed -n '52p' # methode een sed '52!d' # methode twee sed '52q;d' # methode drie, efficient met grote bestanden # beginnend bij regel drie, print iedere zevende regel. gsed -n '3~7p' # alleen GNU sed sed -n '3,${p;n;n;n;n;n;n;}' # andere seds # print deel van bestand tussen twee reguliere expressies (inclusief). sed -n '/Amsterdam/,/Rotterdam/p' # hoofdletter gevoelig SELECTIEVE VERWIJDERING VAN REGELS: # print alle regels behalve die tussen twee reguliere expressies. sed '/Amsterdam/,/Rotterdam/d' # verwijder dubbele en op elkaar volgende regels (emuleert "uniq"). # de eerste regel in een duplicaat set wordt behouden, de rest verwijderd. sed '$!N; /^\(.*\)\n\1$/!P; D' # verwijder dubbele, niet op elkaar volgende, regels. Pas op dat de # beschikbare ruimte in de bewaarbuffer (hold space) niet wordt # overschreden, gebruik anders GNU sed. sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P' # verwijder alle regels behalve duplicaten (emuleert "uniq -d"). sed '$!N; s/^\(.*\)\n\1$/\1/; t; D' # verwijder de eerste tien regels van een bestand. sed '1,10d' # verwijder de laatste regel van een bestand. sed '$d' # verwijder de laatste twee regels van een bestand. sed 'N;$!P;$!D;$d' # verwijder de laatste tien regels van een bestand. sed -e :a -e '$d;N;2,10ba' -e 'P;D' # methode een sed -n -e :a -e '1,10!{P;N;D;};N;ba' # methode twee # verwijder iedere achtste regel. gsed '0~8d' # alleen GNU sed sed 'n;n;n;n;n;n;n;d;' # andere seds # verwijder regels die overeen komen met zoekpatroon. sed '/patroon/d' # verwijder alle lege regels (gelijk aan "grep '.' ") sed '/^$/d' # methode een sed '/./!d' # methode twee # verwijder alle opeenvolgende lege regels behalve de eerste; verwijdert # tevens alle lege regels van begin en einde van het bestand. # (emuleert "cat -s") sed '/./,/^$/!d' # methode een, lege regel aan einde toegestaan sed '/^$/N;/\n$/D' # methode twee, lege regel aan begin toegestaan # verwijder alle opeenvolgende lege regels behalve de eerste twee. sed '/^$/N;/\n$/N;//D' # verwijder alle lege regels aan het begin van het bestand. sed '/./,$!d' # verwijder alle lege regels aan het einde van het bestand. sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' # werkt op alle sed versies sed -e :a -e '/^\n*$/N;/\n$/ba' # idem, behalve gsed 3.02.* # verwijder de laatste regel van iedere paragraaf. sed -n '/^$/{p;h;};/./{x;/./p;}' SPECIALE TOEPASSINGEN: # verwijder nroff overslag (meervoudige afdruk van een karakter) uit # handleidingspagina's (man pages). Bij gebruik van Unix System V of de # bash shell moet de -e switch bij het echo commando gebruikt worden. sed "s/.`echo \\\b`//g" # dubbele aanhalingstekens verplicht in Unix sed 's/.^H//g' # bash/tcsh: druk op Ctrl-V en Ctrl-H sed 's/.\x08//g' # hex expressie voor sed 1.5, GNU sed, ssed # print Usenet/e-mail message header sed '/^$/q' # verwijdert alles na de eerste lege regel # print Usenet/e-mail message body sed '1,/^$/d' # verwijdert alles tot en met eerste lege regel # print Onderwerp-regel, maar verwijder "Onderwerp: " deel sed '/^Onderwerp: */!d; s///;q' # print retour adres sed '/^Reply-To:/q; /^From:/h; /./d;g;q' # selecteer het werkelijke adres. Haalt uit de uitvoer van het vorige # het e-mail adres. sed 's/ *(.*)//; s/>.*//; s/.*[:<] *//' # print een groter-dan teken en een spatie vooraan iedere regel # ("quote a message") sed 's/^/> /' # verwijder groter-dan teken en spatie vooraan iedere regel # ("unquote a message") sed 's/^> //' # verwijder het meerendeel van de HTML tags. Houdt rekenening met # tags verspreid over meerdere regels. sed -e :a -e 's/<[^>]*>//g;/</N;//ba' # extraheer, uit meerdere delen bestaande, uuencoded binaire bestanden # waarbij alle overbodige informatie wordt verwijderd. Bestanden # moeten in de juiste volgorde worden aangeboden. Versie een kan # vanaf de commandoregel worden ingegeven; versie twee kan worden # opgenomen in een Unix shell script (Aangepaste versie van een script # door Rahul Dhesi.) sed '/^end/,/^begin/d' file1 file2 ... fileX | uudecode # versie een sed '/^end/,/^begin/d' "$@" | uudecode # versie twee # sorteer paragrafen in een bestand alfabetisch. Paragrafen worden # gescheiden door een lege regel. GNU sed gebruikt \v (verticale TAB), maar # iedere andere unieke string kan worden gebruikt, zoals "={NL}=" hier. sed '/./{H;d;};x;s/\n/={NL}=/g' file | sort | sed '1s/={NL}=//;s/={NL}=/\n/g' gsed '/./{H;d};x;y/\n/\v/' file | sort | sed '1s/\v//;y/\v/\n/' # Maak een DOS batchfile dat iedere .TXT bestand inpakt in een .ZIP # bestand waarna het bronbestand wordt verwijderd. (Het "dir /b" # commando maakt een lijst van kale bestandsnamen in hoofdletters) echo @echo off >zipup.bat dir /b *.txt | sed "s/^\(.*\)\.TXT/pkzip -mo \1 \1.TXT/" >>zipup.bat TYPISCH GEBRUIK: sed leest een of meer commando's en laat deze allemaal, in de opgegeven volgorde, los op iedere regel van de invoer. Nadat alle commando's zijn losgelaten op de eerste invoerregel wordt de inhoud van de buffer geschreven naar de uitvoer en wordt de volgende regel gelezen van de invoer en herhaalt de cyclus zich. Er wordt hier vanuit gegaan dat de invoer komt van "standaard invoer", d.w.z. de console of via het pipe- mechanisme. Als alternatief kunnen een of meer bestandsnamen op de commandoregel worden gespecificeerd, deze worden dan gelezen als alternatief voor de standaard invoer. Uitvoer wordt geschreven naar "standaard uitvoer". Dit kan naar een bestand worden gestuurd met ">" of naar een ander proces d.m.v. een pipe symbool. Voorbeelden: cat bestand | sed '10q' # gebruik pipe invoer sed '10q' bestand # hetzelfde effect, vermijdt overbodige cat sed '10q' bestand >nieuwbestand # stuurt uitvoer naar bestand op schijf Voor meer syntaxinstructies, inclusief de manier om commando's in een bestand te gebruiken in plaats van via de commando-regel, raadpleeg "sed & awk, 2nd Edition" door Dale Dougherty en Arnold Robbins (O'Reilly, 1997; http://www.ora.com), "UNIX Text Processing" door Dale Dougherty en Tim O'Reilly (Hayden Books, 1987) of de tutorials van Mike Arst die zijn gedistribueerd in U-SEDIT2.ZIP, te vinden op vele websites. Om volledig gebruik te kunnen maken van de kracht van sed moet het begrip "reguliere expressie" worden begrepen. Zie hiervoor "Mastering Regular Expressions" door Jeffrey Friedl (O'Reilly, 1997). De handboek pagina's ("man") op Unix systemen kunnen behulpzaam zijn (probeer "man sed", "man regexp" of het onderdeel over reguliere expressies in "man ed") maar deze pagina's staan niet bekend om hun leesbaarheid. Ze zijn niet bedoeld als leermiddel voor nieuwe gebruikers maar als referentiemiddel voor diegenen die al bekend zijn met deze hulpmiddelen. SYNTAX VAN AANHALINGSTEKENS: De hierboven genoemde voorbeelden gebruiken enkele aanhalingstekens ('...') in plaats van dubbele ("...") om sed commando's te omsluiten omdat sed typisch gebruikt wordt op het Unix platform. De enkele aanhalingstekens verhinderen dat de Unix shell bijzondere karakters, zoals het dollar teken ($) en de "enkele achterwaartse aanhalingsteken" (Engels: backquote), interpreteert die wel worden geïnterpreteerd als ze worden omsloten door dubbele aanhalingstekens. Wie de "csh" shell (of afgeleiden) gebruikt zal tevens de uitroepteken (!) moeten laten voorafgaan door een "backslash" (dus \!) om de voorbeelden succesvol te kunnen gebruiken, zelfs als het wordt omsloten door enkele aanhalingstekens. Voor DOS geschreven versies van sed gebruiken altijd dubbele aanhalingstekens in plaats van enkele zoals hierboven beschreven. GEBRUIK VAN '\t' IN SED SCRIPTS: Voor duidelijkheid in documentatie gebruiken we de term '\t' om het tab karakter (0x09) in scripts aan te duiden. Echter, de meeste versies van sed herkennen de afkorting '\t' niet, dus wanneer deze scripts vanaf de commandoregel worden ingetikt dan dient de TAB toets te worden gebruikt. In awk, perl, HHsed, sedmod en GNU sed v3.02.80 wordt '\t' wel als zodanig herkend als reguliere expressie metakarakter. VERSIES VAN SED: er bestaan diverse verschillende versies van sed zodat variaties in syntax verwacht mogen worden. In het bijzonder kennen de meeste versies niet het gebruik van labels (:naam) of spronginstructies (b,t) binnen commando's, behalve aan het eind van die commando's. We hebben hier de syntax gebruikt die bruikbaar is in de meeste versies van sed hoewel de populaire GNU versies van sed soms beter mogelijkheden bieden. Als we een behoorlijk lang commando zien als dit: sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d dan is het goed te weten dat dit onder GNU sed korter kan: sed '/AAA/b;/BBB/b;/CCC/b;d' # or zelfs sed '/AAA\|BBB\|CCC/b;d' Onthoud dat hoewel veel sed versies een commando als "/one/ s/RE1/RE2/" accepteren, sommige "/one/! s/RE1/RE2/" juist NIET accepteren vanwege de spatie voor de 's'. Laat dan die spaties weg bij het intypen. OPTIMALISEREN VOOR SNELHEID: Als executiesnelheid van belang is (bij een groot invoerbestand of een langzame processor of schijf) dan is het goed te weten dat een substitutie sneller wordt uitgevoerd als de "zoek" expressie op dezelfde regel wordt opggeven VOOR de "s/.../.../" instructie: sed 's/foo/bar/g' bestand # eenvoudige vervanging sed '/foo/ s/foo/bar/g' bestand # dit werkt sneller sed '/foo/ s//bar/g' bestand # nog kortere sed syntax In het geval van selectie of verwijdering waarbij alleen regels in het eerste deel van een groot bestand worden verwerkt zal een "quit" commando (q) in het script de doorlooptijd drastisch beperken: sed -n '45,50p' bestand # print regels 45 tot en met 50 sed -n '51q;45,50p' bestand # hetzelfde, maar veel sneller Mocht je scripts willen bijdragen aan deze lijst, of als je fouten vindt in dit document, stuur dan een e-mail naar de samensteller. Geef hierbij aan welk besturingssysteem je gebruikt, welke versie van sed en de aard van je probleem of onderwerp. Om in aanmerking te komen voor de kwalificatie "one-liner" mag de commando-regel niet langer zijn dan 65 karakters. Bijdragen aan dit document werden geleverd door: Al Aab # oprichter van de "seders" list Edgar Allen # diverse Yiorgos Adamopoulos # diverse Dale Dougherty # auteur van "sed & awk" Carlos Duarte # auteur van "do it with sed" Eric Pement # auteur van dit dokument Ken Pizzini # auteur van GNU sed v3.02 S.G. Ravenhall # auteur van het geweldige de-html script Greg Ubben # diverse bijdragen & veel hulp -------------------------------------------------------------------------