# HG changeset patch # User markus schnalke # Date 1430846460 -7200 # Node ID e67bd0d48bd60dde259d1f5a88998a6d85518bcb # Parent 1dc4a9dca829f7418c418a924abc8e0878fcd8d3 Zwischenstand diff -r 1dc4a9dca829 -r e67bd0d48bd6 cut.txt --- a/cut.txt Tue May 05 09:04:00 2015 +0200 +++ b/cut.txt Tue May 05 19:21:00 2015 +0200 @@ -8,21 +8,22 @@ Cut ist ein klassisches Programm im Unix-Werkzeugkasten. In keinem ordentlichen Tutorial zur Shellprogrammierung fehlt -es. Es ist ein schoenes Anschauungsobjekt fuer's Shellscripting. -Hier soll ein wenig hinter die Fassade von cut geschaut werden. +es, denn es ist ein schoenes, praktisches und anschauliches +Helferlein. Hier soll ein wenig hinter seine Fassade geschaut +werden. Funktionsweise Urspruenglich hatte cut zwei Modi, die spaeter um einen dritten -erweitert wurden. Cut schneidet entweder bestimmte Zeichen aus -den Zeilen der Eingabe oder bestimmte, durch Trennzeichen +erweitert wurden. Cut schneidet entweder gewuenschte Zeichen aus +den Zeilen der Eingabe oder gewuenschte, durch Trennzeichen definierte, Felder. -Der Zeichenmodus ist geeignet um Festbreitenformaten zu +Der Zeichenmodus ist optimal geeignet um Festbreitenformate zu zerteilen. So kann man damit beispielsweise bestimmte -Zugriffsrechte aus der Ausgabe von `ls -l' ausschneiden. Hier -die Rechte des Besitzers: +Zugriffsrechte aus der Ausgabe von `ls -l' ausschneiden, in +diesem Beispiel die Rechte des Besitzers: $ ls -l foo | cut -c 2-4 rw- @@ -49,7 +50,7 @@ sowohl Ausgabezeichen als auch Bytes. Mit dem Aufkommen von Multibyte-Kodierungen (wie UTF-8) musste man sich jedoch von dieser Annahme loesen. In diesem Zug bekam cut mit -POSIX.2-1992 einen Bytemodus mit der Option `-b'. Will man +POSIX.2-1992 einen Bytemodus (Option `-b'). Will man also nur die ersten maximal 500 Bytes vor dem Newline-Zeichen stehen haben (und den Rest stillschweigend ignorieren), dann macht man das mit: @@ -71,14 +72,18 @@ Benutername, seine ID und das Homeverzeichnis: $ cut -d: -f1,3,6 /etc/passwd + root:0:/root + bin:1:/bin + daemon:2:/sbin + mail:8:/var/spool/mail + ... (Die Argumente fuer die Optionen koennen bei cut uebrigens mit Whitespace abgetrennt oder direkt angehaengt folgen.) - Dieser Feld-Modus ist fuer einfache tabellarische Dateien, wie eben die passwd, gut geeignet. Er kommt aber schnell an -seine Grenzen. Gerade der uebliche Fall, dass an Whitespace +seine Grenzen. Gerade der haeufige Fall, dass an Whitespace in Felder geteilt werden soll, wird damit nicht abgedeckt. Der Delimiter kann nur genau ein Zeichen sein. Es kann also nicht sowohl an Leerzeichen als auch an Tabs getrennt werden. @@ -87,9 +92,10 @@ Verhalten widerspricht den Erwartungen, die man an die Verarbeitung einer Datei mit Whitespace-getrennten Feldern hat. Manche Implementierungen von cut, z.B. die von FreeBSD, -haben Erweiterungen, die das gewuenschte Verhalten fuer +haben aber Erweiterungen, die das gewuenschte Verhalten fuer Whitespace-getrennte Felder bieten. Ansonsten, d.h. wenn -man portabel bleiben will, hilft awk. +man portabel bleiben will, verwendet man awk in diesen +Faellen. Awk bietet noch eine weitere Funktion, die cut missen laesst: Das Tauschen der Feld-Reihenfolge in der Ausgabe. Bei @@ -98,10 +104,11 @@ von `cut -c 5-8,1,4-6' die Zeichen Nummer 1, 4, 5, 6, 7 und 8 in genau dieser Reihenfolge aus. Die Auswahl entspricht damit der Mengenlehre in der Mathematik: Jedes angegebene Feld wird -Teil der Ergebnismenge sein. Die Felder der Ergebnismenge sind -dabei immer gleich geordnet wie sie es in der Eingabe waren. -Oder, um die Worte der Manpage in Version 8 Unix -wiederzugeben: ``In data base parlance, it projects a relation.'' +Teil der Ergebnismenge. Die Felder der Ergebnismenge sind +dabei immer gleich geordnet wie in der Eingabe. Um die Worte +der Manpage XXX von Version 8 Unix wiederzugeben: ``In data base +parlance, it projects a relation.'' +[ XXX Cut fuehrt also die Datenbankoperation Projektion auf Textdateien aus. Die Wikipedia erklaert das in verstaendlicherer Sprache: @@ -116,8 +123,6 @@ [ http://de.wikipedia.org/wiki/Projektion_(Informatik)#Projektion - - Geschichtliches Cut erblickte 1982 mit dem Release von UNIX System III das @@ -130,6 +135,7 @@ Quellcode von Version 1.5. Es muss also noch eine Vorgeschichte geben. Zu dieser habe ich leider keinen Zugang gefunden. +XXX mail an TUHS Aber werfen wir doch einen Blick auf die BSD-Linie: Dort ist mein fruehester Fund ein cut.c mit dem Dateimodifikationsdatum @@ -149,6 +155,7 @@ Seine Manpage [ http://minnie.tuhs.org/cgi-bin/utree.pl?file=4.3BSD-Reno/src/usr.bin/cut/cut.1 erwaehnt bereits die erwartete Konformitaet mit POSIX.2. +XXX 2 oder 3 modi? Nun sollte man wissen, dass POSIX.2 erst im September 1992 veroeffentlicht wurde, also gut zwei Jahren *nachdem* die Manpage und das Programm geschrieben wurden. Das Programm @@ -157,39 +164,42 @@ den Standardisierungsprozess geflossen; bis zur Fertigstellung sollte es aber noch weitere zwei Jahre dauern. +Das cut der GNU Coreutils enthaelt einen Copyrightvermerk von +David M. Ihnat aus dem Jahr 1984. + Trotz all dieser Jahreszahlen aus den 80er Jahren gehoert cut aus Sicht des urspruenglichen Unix zu den juengeren Tools. Wenn cut auch ein Jahrzehnt aelter als Linux, der Kernel, ist, so war Unix doch schon ueber zehn Jahre alt, als cut das -erste Mal auftauchte. Insbesondere gehoerte cut noch nicht +erste Mal auftauchte. Insbesondere gehoerte cut auch noch nicht zu Version 7 Unix, das die Ausgangsbasis aller modernen Unix-Systeme darstellt. Die weit komplexeren Programme sed und awk waren dort schon vertreten. Man muss sich also fragen, warum cut ueberhaupt noch entwickelt wurde, wo es -schon zwei Programme gab, die die Aufgabe von cut abdeckten. -Ein Argument fuer cut war sicher seine Kompaktheit und +schon zwei Programme gab, die die Funktion von cut abdecken +konnten. Ein Argument fuer cut war sicher seine Kompaktheit und die damit verbundene Geschwindigkeit gegenueber dem damals traegen awk. Diese schlanke Gestalt ist es auch, die der Unix Philosopie entspricht: Mache eine Aufgabe und die richtig! -So bewaehrte sich cut. Es wurde in andere Unix Varianten -uebernommen, standardisiert und ist heutzutage ueberall -anzutreffen. +Cut ueberzeugte. Es wurde in andere Unix Varianten uebernommen, +standardisiert und ist heutzutage ueberall anzutreffen. -Die urspruengliche Variante (ohne -b) tauchte schon 1985 in +Die urspruengliche Variante (ohne -b) wurde schon 1985 in der System V Interface Definition, einer wichtigen formalen -Beschreibung von UNIX System V, und in allen relevanten -Standards seither auf. Mit POSIX.2 im Jahre 1992 wurde cut -zum ersten Mal in der heutigen Form (mit -b) standardisiert. +Beschreibung von UNIX System V, spezifiziert und tauchte +anschliessend in allen relevanten Standards auf. Mit POSIX.2 +im Jahre 1992 wurde cut zum ersten Mal in der heutigen Form +(mit -b) standardisiert. +XXX sicher? s.o. - -Multibyte-Behandlung +Multibyte-Unterstuetzung Nun sind der Bytemodus und die damit verbundene Multibyte-Verarbeitung des POSIX-Zeichenmodus bereits seit 1992 standardisiert, wie steht es aber mit deren Umsetzung? Welche Versionen implementieren denn den POSIX korrekt? -Die Situation ist mehrschichtig. Es gibt traditionelle +Die Situation ist dreiteilig: Es gibt traditionelle Implementierungen, die nur -c und -f kennen. Dann gibt es Implementierungen die zwar -b kennen, es aber nur als Alias fuer -c handhaben. Diese Implementierungen funktionieren mit @@ -203,8 +213,8 @@ System III, System V und die aller BSDs bis in die 90er. Pseude-Multibyte-Implementierungen bieten GNU und die -modernen NetBSDs und OpenBSDs. Wie sehr dort der Schein von -POSIX-konformitaet gewahrt wird, ist unterschiedlich. Nicht +modernen NetBSDs und OpenBSDs. Wie sehr dort ein Schein von +POSIX-Konformitaet gewahrt wird, ist unterschiedlich. Nicht immer findet man klare Aussagen wie diese: /* Since we don't support multi-byte characters, the -c and -b @@ -215,7 +225,7 @@ Tatsaechlich standardkonforme Implementierungen, die Multibytes korrekt handhaben, bekommt man bei einem modernen FreeBSD und bei den Heirloom Tools. Bei FreeBSD hat Tim Robbins -(tjr) im Sommer 2004 den Zeichenmodus POSIX-konform reimplementiert. +im Sommer 2004 den Zeichenmodus POSIX-konform reimplementiert. [ https://svnweb.freebsd.org/base?view=revision&revision=131194 Warum die beiden anderen grossen BSDs diese Aenderung nicht uebernommen haben, bleibt offen. Es scheint aber an der im @@ -224,12 +234,12 @@ Wie findet man als Nutzer heraus, ob beim cut(1) des eigenen Systems Multibytes korrekt unterstuetzt werden? Zuerst ist entscheidend, ob das System selbst mit einem Multibyte-Encoding -arbeitet, denn tut es das nicht, dann entsprechen sich Zeichen -und Bytes und die Frage eruebrigt sich. Man kann dazu nachschauen, -welches Locale eingestellt ist, aber einfacher ist es, ein -typisches Mehrbytezeichen, wie z.B. einen Umlaut, auszugeben -und zu schauen ob dieses in einem oder in mehreren Bytes -kodiert ist: +arbeitet, denn tut es das nicht, dann entsprechen sich naemlich +Zeichen und Bytes und die Frage eruebrigt sich. Man kann das +herausfinden indem man sich das Locale anschaut, aber einfacher +ist es, ein typisches Mehrbytezeichen, wie z.B. einen Umlaut, +auszugeben und zu schauen ob dieses in einem oder in mehreren +Bytes kodiert ist: $ echo รค | od -c 0000000 303 244 \n @@ -238,7 +248,7 @@ In diesem Fall sind es zwei Bytes: oktal 303 und 244 . (Den Zeilenumbruch fuegt echo(1) hinzu.) -Mit dem Programm iconv(1) kann man Test explizit in bestimmte +Mit dem Programm iconv(1) kann man Text explizit in bestimmte Kodierungen konvertieren. Hier Beispiele, wie das Ergebnis bei Latin1 und wie es bei UTF-8 aussieht. @@ -273,110 +283,95 @@ werden die ersten beiden Bytes ausgegeben. - Implementierungen -Nun zum Blick auf den Code. Hier soll eine Auswahl an -Implementierungen etwas genauer betrachtet werden. Fuer einen -ersten Eindruck ist der Umfang des Quellcodes hilfreich. -Typischerweise steigt dieser ueber die Jahre an. Diese +Nun ein Blick auf den Code. Betrachtet wird eine Auswahl an +Implementierungen. + +Fuer einen ersten Eindruck ist der Umfang des Quellcodes +hilfreich. Typischerweise steigt dieser ueber die Jahre an. Diese Beobachtung kann hier in der Tendenz, aber nicht in jedem Fall, -bestaetigt werden. +bestaetigt werden. Die Unterstuetzung des Byte-Modus (-b) +erfordert zwangslaeufig mehr Code, deshalb sind die +POSIX-konformen Implementierungen tendenziell umfangreicher. -Die Unterstuetzung des Byte-Modus (-b) erfordert zwangslaeufig -mehr Code, deshalb ist zu erwarten, dass diejenigen -Implementierungen, die ihn haben, umfangreicher sind. -Codevergleich + SLOC Zeilen Bytes Gehoert zu Dateidatum Kategorie + ----------------------------------------------------------------- + 116 123 2966 System III 1980-04-11 (trad) + 118 125 3038 4.3BSD-UWisc 1986-11-07 (trad) + 200 256 5715 4.3BSD-Reno 1990-06-25 (trad) + 200 270 6545 NetBSD 1993-03-21 (trad) + 218 290 6892 OpenBSD 2008-06-27 (pseudo) + 224 296 6920 FreeBSD 1994-05-27 (trad) + 232 306 7500 NetBSD 2014-02-03 (pseudo) + 340 405 7423 Heirloom 2012-05-20 (POSIX) + 382 586 14175 GNU coreutils 1992-11-08 (pseudo) + 391 479 10961 FreeBSD 2012-11-24 (POSIX) + 588 830 23167 GNU coreutils 2015-05-01 (pseudo) +XXX verlinken -SLOC Zeilen Bytes Gehoert zu Dateidatum Kategorie ------------------------------------------------------------------ -116 123 2966 System III 1980-04-11 (trad) -118 125 3038 4.3BSD-UWisc 1986-11-07 (trad) -200 256 5715 4.3BSD-Reno 1990-06-25 (trad) -200 270 6545 NetBSD 1993-03-21 (trad) -218 290 6892 OpenBSD 2008-06-27 (pseudo) -224 296 6920 FreeBSD 1994-05-27 (trad) -232 306 7500 NetBSD 2014-02-03 (pseudo) -340 405 7423 Heirloom 2012-05-20 (POSIX) -382 586 14175 GNU coreutils 1992-11-08 (pseudo) -391 479 10961 FreeBSD 2012-11-24 (POSIX) -588 830 23167 GNU coreutils 2015-05-01 (pseudo) +Das Kandidatenfeld teilt sich grob in vier Gruppen: (1) Die zwei +urspruenglichen Implementierungen, die sich nur minimal +unterscheiden, mit gut 100 SLOCs. (2) Die fuenf BSD-Versionen mit +gut 200 SLOCs. (3) Die zwei POSIX-konformen Programme und +die alte GNU-Version mit 340-390 SLOCs. Und (4) die moderne +GNU-Variante mit fast 600 SLOCs. -$ awk -F' +' '{printf("%d\t%d (%.2f)\t%d (%.2f)\t%s\t%s\t%s\n", - $1, $2, $2/$1, $3, $3/$1, $4, $5, $6);}'