docs/cut

view cut.txt @ 9:e67bd0d48bd6

Zwischenstand
author markus schnalke <meillo@marmaro.de>
date Tue, 05 May 2015 19:21:00 +0200
parents 1dc4a9dca829
children 7e1214b556b9
line source
1 Das Werkzeugkaestle, #1
3 cut - cut out selected fields of each line of a file
4 ----------------------------------------------------
5 markus schnalke <meillo@marmaro.de>
6 2015-05
9 Cut ist ein klassisches Programm im Unix-Werkzeugkasten.
10 In keinem ordentlichen Tutorial zur Shellprogrammierung fehlt
11 es, denn es ist ein schoenes, praktisches und anschauliches
12 Helferlein. Hier soll ein wenig hinter seine Fassade geschaut
13 werden.
16 Funktionsweise
18 Urspruenglich hatte cut zwei Modi, die spaeter um einen dritten
19 erweitert wurden. Cut schneidet entweder gewuenschte Zeichen aus
20 den Zeilen der Eingabe oder gewuenschte, durch Trennzeichen
21 definierte, Felder.
23 Der Zeichenmodus ist optimal geeignet um Festbreitenformate zu
24 zerteilen. So kann man damit beispielsweise bestimmte
25 Zugriffsrechte aus der Ausgabe von `ls -l' ausschneiden, in
26 diesem Beispiel die Rechte des Besitzers:
28 $ ls -l foo | cut -c 2-4
29 rw-
31 Oder die Schreibrechte des Besitzers, der Gruppe und der
32 Welt:
34 $ ls -l | cut -c 3,6,9
35 ww-
37 Mit cut lassen sich aber auch Strings kuerzen.
39 $ echo "$long" | cut -c -20
41 Dieser Befehl gibt die ersten maximal 20 Zeichen von
42 `$long' aus. (Alternativ kann man hierfuer auch `printf
43 "%.20s\n" "$long"' verwenden.)
45 Geht es aber nicht um die Darstellung von Zeichen, sondern um
46 ihre Speicherung, dann ist `-c' nicht unbedingt geeignet.
47 Frueher, als US-ASCII als Zeichensatz und -kodierung
48 noch omnipraesent war, wurde jedes Zeichen mit genau einem
49 Byte gespeichert. Somit selektierte `cut -c' gleichermassen
50 sowohl Ausgabezeichen als auch Bytes. Mit dem Aufkommen von
51 Multibyte-Kodierungen (wie UTF-8) musste man sich jedoch von
52 dieser Annahme loesen. In diesem Zug bekam cut mit
53 POSIX.2-1992 einen Bytemodus (Option `-b'). Will man
54 also nur die ersten maximal 500 Bytes vor dem
55 Newline-Zeichen stehen haben (und den Rest stillschweigend
56 ignorieren), dann macht man das mit:
58 $ cut -b -500
60 Den Rest kann man sich mit `cut -b 501-' einfangen. Diese
61 Funktion ist insbesondere fuer POSIX wichtig, da man so
62 Textdateien mit begrenzter Zeilenlaenge erzeugen kann.
63 [ http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cut.html#tag_20_28_17
65 Neben dem Zeichen- bzw. Byte-Modus bietet cut noch den
66 Feld-Modus, den man mit `-f' einleitet. Mit ihm
67 koennen Felder ausgewaehlt werden. Das Trennzeichen (per
68 Default der Tab) kann mit `-d' geaendert werden.
70 Der typische Anwendungsfall fuer cut im Feld-Modus ist die
71 Auswahl von Information aus der passwd-Datei. So z.B. der
72 Benutername, seine ID und das Homeverzeichnis:
74 $ cut -d: -f1,3,6 /etc/passwd
75 root:0:/root
76 bin:1:/bin
77 daemon:2:/sbin
78 mail:8:/var/spool/mail
79 ...
81 (Die Argumente fuer die Optionen koennen bei cut uebrigens
82 mit Whitespace abgetrennt oder direkt angehaengt folgen.)
84 Dieser Feld-Modus ist fuer einfache tabellarische Dateien,
85 wie eben die passwd, gut geeignet. Er kommt aber schnell an
86 seine Grenzen. Gerade der haeufige Fall, dass an Whitespace
87 in Felder geteilt werden soll, wird damit nicht abgedeckt.
88 Der Delimiter kann nur genau ein Zeichen sein. Es kann also
89 nicht sowohl an Leerzeichen als auch an Tabs getrennt werden.
90 Auch unterteilt cut an jedem Trennzeichen. Zwei aneinander
91 stehende Trennzeichen fuehren zu einem leeren Feld. Dieses
92 Verhalten widerspricht den Erwartungen, die man an die
93 Verarbeitung einer Datei mit Whitespace-getrennten Feldern
94 hat. Manche Implementierungen von cut, z.B. die von FreeBSD,
95 haben aber Erweiterungen, die das gewuenschte Verhalten fuer
96 Whitespace-getrennte Felder bieten. Ansonsten, d.h. wenn
97 man portabel bleiben will, verwendet man awk in diesen
98 Faellen.
100 Awk bietet noch eine weitere Funktion, die cut missen
101 laesst: Das Tauschen der Feld-Reihenfolge in der Ausgabe. Bei
102 cut ist die Reihenfolge der Feldauswahlangabe irrelevant; ein
103 Feld kann selbst mehrfach angegeben werden. So gibt der Aufruf
104 von `cut -c 5-8,1,4-6' die Zeichen Nummer 1, 4, 5, 6, 7 und 8
105 in genau dieser Reihenfolge aus. Die Auswahl entspricht damit
106 der Mengenlehre in der Mathematik: Jedes angegebene Feld wird
107 Teil der Ergebnismenge. Die Felder der Ergebnismenge sind
108 dabei immer gleich geordnet wie in der Eingabe. Um die Worte
109 der Manpage XXX von Version 8 Unix wiederzugeben: ``In data base
110 parlance, it projects a relation.''
111 [ XXX
112 Cut fuehrt also die Datenbankoperation Projektion auf
113 Textdateien aus. Die Wikipedia erklaert das in
114 verstaendlicherer Sprache:
116 Die Projektion entspricht der Projektionsabbildung aus der
117 Mengenlehre und kann auch Attributbeschränkung genannt
118 werden. Sie extrahiert einzelne Attribute aus der
119 ursprünglichen Attributmenge und ist somit als eine Art
120 Selektion auf Spaltenebene zu verstehen, das heißt, die
121 Projektion blendet Spalten aus.
123 [ http://de.wikipedia.org/wiki/Projektion_(Informatik)#Projektion
126 Geschichtliches
128 Cut erblickte 1982 mit dem Release von UNIX System III das
129 Licht der oeffentlichen Welt. Wenn man die Quellen von System
130 III durchforstet, findet man die Quellcodedatei cut.c mit dem
131 Zeitstempel 1980-04-11.
132 [ http://minnie.tuhs.org/cgi-bin/utree.pl?file=SysIII/usr/src/cmd
133 Das ist die aelteste Manifestation des Programms, die ich
134 aufstoebern konnte. Allerdings spricht die sccsid im
135 Quellcode von Version 1.5. Es muss also noch eine
136 Vorgeschichte geben. Zu dieser habe ich leider keinen Zugang
137 gefunden.
138 XXX mail an TUHS
140 Aber werfen wir doch einen Blick auf die BSD-Linie: Dort ist mein
141 fruehester Fund ein cut.c mit dem Dateimodifikationsdatum
142 1986-11-07
143 [ http://minnie.tuhs.org/cgi-bin/utree.pl?file=4.3BSD-UWisc/src/usr.bin/cut
144 als Teil der Spezialversion 4.3BSD-UWisc,
145 [ http://gunkies.org/wiki/4.3_BSD_NFS_Wisconsin_Unix
146 die im Januar 1987 veroeffentlicht wurde.
147 Die Implementierung unterscheidet sich nur minimal von der
148 in System III.
149 Im bekannteren 4.3BSD-Tahoe (1988) taucht cut nicht auf.
150 Das darauf folgende 4.3BSD-Reno (1990) liefert aber wieder
151 ein cut mit aus. Dieses cut ist ein von Adam S. Moskowitz und
152 Marciano Pitargue neu implementiertes cut, das 1989 in BSD
153 aufgenommen wurde.
154 [ http://minnie.tuhs.org/cgi-bin/utree.pl?file=4.3BSD-Reno/src/usr.bin/cut
155 Seine Manpage
156 [ http://minnie.tuhs.org/cgi-bin/utree.pl?file=4.3BSD-Reno/src/usr.bin/cut/cut.1
157 erwaehnt bereits die erwartete Konformitaet mit POSIX.2.
158 XXX 2 oder 3 modi?
159 Nun sollte man wissen, dass POSIX.2 erst im September
160 1992 veroeffentlicht wurde, also gut zwei Jahren *nachdem* die
161 Manpage und das Programm geschrieben wurden. Das Programm
162 wurde also anhand von Arbeitsversionen des Standards
163 implementiert. Zweieinhalb Jahre Arbeit war immerhin schon in
164 den Standardisierungsprozess geflossen; bis zur
165 Fertigstellung sollte es aber noch weitere zwei Jahre dauern.
167 Das cut der GNU Coreutils enthaelt einen Copyrightvermerk von
168 David M. Ihnat aus dem Jahr 1984.
170 Trotz all dieser Jahreszahlen aus den 80er Jahren gehoert cut
171 aus Sicht des urspruenglichen Unix zu den juengeren Tools.
172 Wenn cut auch ein Jahrzehnt aelter als Linux, der Kernel, ist,
173 so war Unix doch schon ueber zehn Jahre alt, als cut das
174 erste Mal auftauchte. Insbesondere gehoerte cut auch noch nicht
175 zu Version 7 Unix, das die Ausgangsbasis aller modernen
176 Unix-Systeme darstellt. Die weit komplexeren Programme sed
177 und awk waren dort schon vertreten. Man muss sich also
178 fragen, warum cut ueberhaupt noch entwickelt wurde, wo es
179 schon zwei Programme gab, die die Funktion von cut abdecken
180 konnten. Ein Argument fuer cut war sicher seine Kompaktheit und
181 die damit verbundene Geschwindigkeit gegenueber dem damals
182 traegen awk. Diese schlanke Gestalt ist es auch, die der Unix
183 Philosopie entspricht: Mache eine Aufgabe und die richtig!
184 Cut ueberzeugte. Es wurde in andere Unix Varianten uebernommen,
185 standardisiert und ist heutzutage ueberall anzutreffen.
187 Die urspruengliche Variante (ohne -b) wurde schon 1985 in
188 der System V Interface Definition, einer wichtigen formalen
189 Beschreibung von UNIX System V, spezifiziert und tauchte
190 anschliessend in allen relevanten Standards auf. Mit POSIX.2
191 im Jahre 1992 wurde cut zum ersten Mal in der heutigen Form
192 (mit -b) standardisiert.
193 XXX sicher? s.o.
196 Multibyte-Unterstuetzung
198 Nun sind der Bytemodus und die damit verbundene
199 Multibyte-Verarbeitung des POSIX-Zeichenmodus bereits seit
200 1992 standardisiert, wie steht es aber mit deren Umsetzung?
201 Welche Versionen implementieren denn den POSIX korrekt?
202 Die Situation ist dreiteilig: Es gibt traditionelle
203 Implementierungen, die nur -c und -f kennen. Dann gibt es
204 Implementierungen die zwar -b kennen, es aber nur als Alias
205 fuer -c handhaben. Diese Implementierungen funktionieren mit
206 Single-Byte-Encodings (z.B. US-ASCII, Latin1) korrekt, bei
207 Multi-Byte-Encodings (z.B. UTF-8) verhaelt sich ihr -c aber
208 wie -b (und -n wird ignoriert). Schliesslich gibt es noch
209 Implementierungen, die -b und -c tatsaechlich POSIX-konform
210 implementieren.
212 Traditionelle Zwei-Modi-Implementierungen sind z.B. die von
213 System III, System V und die aller BSDs bis in die 90er.
215 Pseude-Multibyte-Implementierungen bieten GNU und die
216 modernen NetBSDs und OpenBSDs. Wie sehr dort ein Schein von
217 POSIX-Konformitaet gewahrt wird, ist unterschiedlich. Nicht
218 immer findet man klare Aussagen wie diese:
220 /* Since we don't support multi-byte characters, the -c and -b
221 options are equivalent, and the -n option is meaningless. */
223 [ XXX
225 Tatsaechlich standardkonforme Implementierungen, die
226 Multibytes korrekt handhaben, bekommt man bei einem modernen
227 FreeBSD und bei den Heirloom Tools. Bei FreeBSD hat Tim Robbins
228 im Sommer 2004 den Zeichenmodus POSIX-konform reimplementiert.
229 [ https://svnweb.freebsd.org/base?view=revision&revision=131194
230 Warum die beiden anderen grossen BSDs diese Aenderung nicht
231 uebernommen haben, bleibt offen. Es scheint aber an der im
232 obigen Kommentar formulierten Grundausrichtung zu liegen.
234 Wie findet man als Nutzer heraus, ob beim cut(1) des eigenen
235 Systems Multibytes korrekt unterstuetzt werden? Zuerst ist
236 entscheidend, ob das System selbst mit einem Multibyte-Encoding
237 arbeitet, denn tut es das nicht, dann entsprechen sich naemlich
238 Zeichen und Bytes und die Frage eruebrigt sich. Man kann das
239 herausfinden indem man sich das Locale anschaut, aber einfacher
240 ist es, ein typisches Mehrbytezeichen, wie z.B. einen Umlaut,
241 auszugeben und zu schauen ob dieses in einem oder in mehreren
242 Bytes kodiert ist:
244 $ echo ä | od -c
245 0000000 303 244 \n
246 0000003
248 In diesem Fall sind es zwei Bytes: oktal 303 und 244 . (Den
249 Zeilenumbruch fuegt echo(1) hinzu.)
251 Mit dem Programm iconv(1) kann man Text explizit in bestimmte
252 Kodierungen konvertieren. Hier Beispiele, wie das Ergebnis
253 bei Latin1 und wie es bei UTF-8 aussieht.
255 $ echo ä | iconv -t latin1 | od -c
256 0000000 344 \n
257 0000002
259 $ echo ä | iconv -t utf8 | od -c
260 0000000 303 244 \n
261 0000003
263 Die Ausgabe auf dem eigenen System (ohne die iconv-Konvertierung)
264 wird recht sicher einer dieser beiden Ausgaben entsprechen.
266 Nun zum Test der cut-Implementierung. Hat man ein UTF-8-System,
267 dann sollte sich eine POSIX-konforme Implementierung so verhalten:
269 $ echo aä | ./cut -c -2 | od -c
270 0000000 a 303 244 \n
271 0000004
273 $ echo aä | ./cut -b -2 | od -c
274 0000000 a 303 \n
275 0000003
277 $ echo aä | ./cut -b -2 -n | od -c
278 0000000 a \n
279 0000002
281 Bei einer Implementierung, die -b und -c gleich behandelt,
282 ist die Ausgabe in allen drei Faellen wie die mittlere: Es
283 werden die ersten beiden Bytes ausgegeben.
286 Implementierungen
288 Nun ein Blick auf den Code. Betrachtet wird eine Auswahl an
289 Implementierungen.
291 Fuer einen ersten Eindruck ist der Umfang des Quellcodes
292 hilfreich. Typischerweise steigt dieser ueber die Jahre an. Diese
293 Beobachtung kann hier in der Tendenz, aber nicht in jedem Fall,
294 bestaetigt werden. Die Unterstuetzung des Byte-Modus (-b)
295 erfordert zwangslaeufig mehr Code, deshalb sind die
296 POSIX-konformen Implementierungen tendenziell umfangreicher.
299 SLOC Zeilen Bytes Gehoert zu Dateidatum Kategorie
300 -----------------------------------------------------------------
301 116 123 2966 System III 1980-04-11 (trad)
302 118 125 3038 4.3BSD-UWisc 1986-11-07 (trad)
303 200 256 5715 4.3BSD-Reno 1990-06-25 (trad)
304 200 270 6545 NetBSD 1993-03-21 (trad)
305 218 290 6892 OpenBSD 2008-06-27 (pseudo)
306 224 296 6920 FreeBSD 1994-05-27 (trad)
307 232 306 7500 NetBSD 2014-02-03 (pseudo)
308 340 405 7423 Heirloom 2012-05-20 (POSIX)
309 382 586 14175 GNU coreutils 1992-11-08 (pseudo)
310 391 479 10961 FreeBSD 2012-11-24 (POSIX)
311 588 830 23167 GNU coreutils 2015-05-01 (pseudo)
312 XXX verlinken
315 Das Kandidatenfeld teilt sich grob in vier Gruppen: (1) Die zwei
316 urspruenglichen Implementierungen, die sich nur minimal
317 unterscheiden, mit gut 100 SLOCs. (2) Die fuenf BSD-Versionen mit
318 gut 200 SLOCs. (3) Die zwei POSIX-konformen Programme und
319 die alte GNU-Version mit 340-390 SLOCs. Und (4) die moderne
320 GNU-Variante mit fast 600 SLOCs.
322 Die Abweichung zwischen logischen Codezeilen (SLOC, ermittelt mit
323 SLOCcount) und der Anzahl von Zeilenumbruechen in der Datei (`wc
324 -l') erstreckt sich ueber einen Faktor von 1.06 bei den aeltesten
325 Vertretern bis zu Faktor 1.5 bei GNU. Der groesste
326 Einflussfaktor darauf sind Leerzeilen, reine Kommentarzeilen und
327 die Groesse des Lizenzblocks am Dateianfang.
329 Betrachtet man die Abweichungen zwischen den logischen Codezeilen
330 und der Dateigroesse (`wc -c'), so pendelt das Teilnehmerfeld
331 zwischen 25 und 30 Bytes je Anweisung. Die Heirloom-Implementierung
332 weicht mit nur 21 nach unten ab, die GNU-Implementierungen mit
333 fast 40 nach oben. Dies liegt bei GNU hauptsaechlich am
334 Programmierstil, mit spezieller Einrueckung und langen Bezeichnern.
335 Ob man die Heirloom-Implementierung als besonders kryptisch
336 oder als besonders elegant bezeichnen will, das soll der
337 eigenen Einschaetzung des Lesers ueberlassen bleiben.
340 Schaut man sich die SCCS-IDs (die vom damaligen
341 Versionskontrollsystem eingefuegt wurden) in den BSD-Quellen an,
342 dann findet man dort Versionsnummern, die die Entwicklung
343 dokumentieren:
345 4.3bsd-uwisc "@(#)cut.c 1.3";
346 4.3bsd-reno "@(#)cut.c 5.3 (Berkeley) 6/24/90";
347 netbsd "@(#)cut.c 5.4 (Berkeley) 10/30/90";
348 freebsd "@(#)cut.c 8.1 (Berkeley) 6/6/93";
350 Die neueren BSD-Versionen enthalten zwar weiterhin eine SCCS-ID, diese
351 ist aber bei Version "8.3 (Berkeley) 5/4/95" stehen geblieben. Danach
352 wurde scheinbar von SCCS auf ein anderes
353 Versionskontrollsystem gewechselt.
354 XXX
356 Bei GNU befindet sich folgender Copyright-Vermerk im Code:
358 Copyright (C) 1997-2015 Free Software Foundation, Inc.
359 Copyright (C) 1984 David M. Ihnat
361 Der Code hat also ziemlich alte Urspruenge. Wie aus weiteren
362 Kommentaren zu entnehmen ist, wurde der Code zuerst von David
363 MacKenzie und spaeter von Jim Meyering ueberarbeitet. Letzterer
364 hat den Code 1992 auch ins Versionkontrollsystem eingestellt.
365 Weshalb die Jahre zwischen 1992 und 1997 nicht im Copyright-Vermerk
366 auftauchen, ist unklar.
369 Beschreibungen
371 Interessant ist auch ein Vergleich der Kurzbeschreibungen von
372 cut, wie sie sich in der Titelzeile von Manpages oder manchmal
373 auch am Anfang der Quellcodedatei finden. Die folgende Liste
374 ist grob zeitlich geordnet und nach Abstammung gruppiert:
377 System III cut out selected fields of each line of a file
378 System III (src) cut and paste columns of a table (projection of a relation)
379 System V cut out selected fields of each line of a file
380 HP-UX cut out (extract) selected fields of each line of a file
382 4.3BSD-UWisc (src) cut and paste columns of a table (projection of a relation)
383 4.3BSD-Reno select portions of each line of a file
384 NetBSD select portions of each line of a file
385 OpenBSD 4.6 select portions of each line of a file
386 FreeBSD 1.0 select portions of each line of a file
387 FreeBSD 7.0 cut out selected portions of each line of a file
388 SunOS 4.1.3 remove selected fields from each line of a file
389 SunOS 5.5.1 cut out selected fields of each line of a file
390 XXX FreeBSD 10
392 Heirloom Tools cut out selected fields of each line of a file
393 Heirloom Tools (src) cut out fields of lines of files
395 GNU coreutils remove sections from each line of files
397 Minix select out columns of a file
399 Version 8 Unix rearrange columns of data
400 ``Unix Reader'' rearrange columns of text
402 POSIX cut out selected fields of each line of a file
405 Die mit ``(src)'' markierten Beschreibungen sind aus dem
406 jeweiligen Quellcode entnommen.
407 Der POSIX-Eintrag enthaelt die Beschreibung des Standards.
408 Der ``Unix Reader'' ist ein rueckblickendes Textdokument von
409 Doug McIlroy, das das Auftreten von Tools in der Geschichte
410 des Research Unix zum Thema hat.
411 [ XXX
412 Eigentlich sollte seine
413 Beschreibung der in Version 8 Unix entsprechen. Die
414 Abweichung koennte sowohl ein Uebertragungsfehler als auch
415 eine nachtraegliche Korrektur sein.
416 Alle uebrigen Beschreibungen entstammen den Manpages.
418 Oft ist mit der Zeit die POSIX-Beschreibung uebernommen
419 worden, wie beispielsweise bei FreeBSD zu sehen.
420 [ https://svnweb.freebsd.org/base?view=revision&revision=167101
421 XXX fixme!
423 Interessant ist, dass die GNU coreutils seit Anbeginn vom
424 Entfernen von Teilen der Eingabe sprechen, wohingegen die
425 Kommandozeilenangabe klar ein Auswaehlen darstellt. Die
426 Worte ``cut out'' sind vielleicht auch etwas
427 missverstaendlich. HP-UX hat sie deshalb praezisiert.
429 Auch beim Begriff, was denn nun selektiert wird, ist man sich
430 uneins. Die einen reden von Feldern (POSIX), andere von
431 Abschnitten bzw. Teilen (BSD) und wieder andere von Spalten
432 (Research Unix). Ironischerweise leistet sich gerade Version
433 8 Unix, das eigentlich um eine sehr treffende Weltsicht
434 bemueht ist, mit ``rearrange columns of data'' die
435 unzutreffendste der Beschreibungen.
438 Autoreninfo
440 Markus Schnalke interessiert sich fuer die Hintergruende
441 von Unix und seinen Werkzeugen. Fuer die Erarbeitung dieses
442 Textes wurde er regelrecht zum Historiker.
445 Lizenz
446 CC0 (und kann damit auch unter CC BY-SA 4.0 Unported
447 veroeffentlicht werden)