view cut.txt @ 6:bf2ac5df0063

Zwischenstand
author markus schnalke <meillo@marmaro.de>
date Sun, 03 May 2015 18:08:00 +0200
parents 00097c80a853
children 21ca59543b07
line wrap: on
line source

Das Werkzeugkaestle, #1

cut - cut out selected fields of each line of a file
----------------------------------------------------
markus schnalke <meillo@marmaro.de>
2015-05


Cut ist ein klassisches Programm im Unix-Werkzeugkasten.
In keinem ordentlichen Tutorial zur Shellprogrammierung darf
es fehlen. Es ist ein schoenes Anschauungs- und Beispielobjekt
fuer's Shellscripting. Hier will ich ein wenig hinter die
Fassade schauen.


Funktionsweise

Die Funktionsbasis von cut waren urspruenglich zwei Modi, die
spaeter um einen dritten erweitert wurden. Cut schneidet
entweder bestimmte Zeichen aus den Zeilen der Eingabe oder
bestimmte durch Trennzeichen definierte Felder.

Der Zeichenmodus ist geeignet um Ausschnitte aus
Festbreitenformaten zu extrahieren. So kann man damit
beispielsweise bestimmte Zugriffsrechte aus der Ausgabe von
`ls -l' ausschneiden. Hier die Rechte des Besitzers:

	$ ls -l foo | cut -c 2-4
	rw-

Oder die Schreibrechte des Besitzers, der Gruppe und der
Welt:

	$ ls -l | cut -c 3,6,9
	ww-

Mit cut lassen sich aber auch Strings kuerzen.

	$ echo "$long" | cut -c -20

Dieser Befehl gibt die ersten maximal 20 Zeichen (jeder
Zeile) von `$long' aus.

Geht es aber nicht um die Darstellung von Zeichen, sondern um
ihre Speicherung, dann ist `-c' nicht unbedingt die passende
Option. Frueher, als US-ASCII als Zeichensatz und -kodierung
noch omnipraesent war, wurde jedes Zeichen mit genau einem
Byte gespeichert. Somit selektierte `cut -c' gleichermassen
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 die Option `-b'. Diese selektiert Bytes. 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:

	$ cut -b -500

Den Rest kann man sich mit `cut -b 501-' einfangen. Diese
Funktion ist insbesondere fuer POSIX wichtig, da so sicher
gestellt werden kann, dass Textdateien keine beliebig
langen Zeilen haben.
[ http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cut.html#tag_20_28_17

Neben dem Zeichen- bzw. Byte-Modus bietet cut noch den
interessanteren Feld-Modus, den man mit `-f' einleitet. Mit ihm
koennen Felder ausgewaehlt werden. Das Trennzeichen (per
Default der Tab) kann mit `-d' geaendert werden.

Der typische Anwendungsfall fuer den Feld-Modus. Ist die
Extraktion von Information aus der passwd-Datei. So z.B. der
Username, die User-ID und das Homeverzeichnis:

	$ cut -d: -f1,3,6 /etc/passwd

(Die Argumente fuer die Optionen koennen bei cut uebrigens
direkt angehaengt oder mit Whitespace abgetrennt 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
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.
Auch unterteilt cut an jedem Trennzeichen. Zwei aneinander
stehende Trennzeichen fuehren zu einem leeren Feld. Dieses
Verhalten widerspricht den Erwartungen fuer eine Datei mit
Whitespace-getrennten Feldern. (Manche Implementierungen von
cut, z.B. die von FreeBSD, haben deshalb Erweiterungen, die
das gewuenschte Verhalten fuer Whitespace-getrennte Felder
bieten.) Ansonsten, d.h. wenn man portabel bleiben will,
hilft awk.

Awk bietet noch eine weitere Funktion, die cut missen
laesst: Das Tauschen der Felder-Reihenfolge. Bei cut ist die
Reihenfolge der Feldauswahl irrelevant; ein Feld kann selbst
mehrfach angegeben werden. Der Aufruf von `cut -c 5-8,1,4-6'
gibt z.B.  die Zeichen Nummer 1, 4, 5, 6, 7 und 8 aus. Die
Auswahl aehnelt damit der Mengenlehre in der Mathematik:
Jedes angegebene Feld soll in der Ergebnismenge sein. Die
Felder der Ergebnismenge werden dabei immer in der gleichen
Reihenfolge ausgegeben wie sie in der Eingabe waren.


Geschichtliches

Cut erblickte 1982 mit dem Release von UNIX System III das
Licht der oeffentlichen Welt. Wenn man die Quellen von System
III durchforstet, findet man die Quellcodedatei cut.c mit dem
Zeitstempel 1980-04-11.
[ http://minnie.tuhs.org/cgi-bin/utree.pl?file=SysIII/usr/src/cmd
Das ist die aelteste Manifestation des Programms, die ich
aufstoebern konnte.

Aber werfen wir doch einen Blick auf die BSD-Linie: Dort ist mein
fruehester Fund ein cut.c mit dem Datum 1986-11-07 im Code der
Spezialversion 4.3BSD-UWisc,
[ http://gunkies.org/wiki/4.3_BSD_NFS_Wisconsin_Unix
die im Januar 1987 veroeffentlicht wurde.
[ http://minnie.tuhs.org/cgi-bin/utree.pl?file=4.3BSD-UWisc/src/usr.bin/cut
Die Datei unterscheidet sich nur minimal von der aus System III.
Im bekannteren 4.3BSD-Tahoe (1988) taucht cut aber nicht auf.
Im darauf folgenden 4.3BSD-Reno (1990) gibt es wiederum ein
cut ... ein von Adam S. Moskowitz und Marciano Pitargue neu
implementiertes cut, das 1989 in BSD aufgenommen wurde.
[ http://minnie.tuhs.org/cgi-bin/utree.pl?file=4.3BSD-Reno/src/usr.bin/cut
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.
Nun sollte man wissen, dass POSIX.2 erst im September
1992 veroeffentlicht wurde, gut zwei Jahren *nachdem* die
Manpage und das Programm geschrieben wurden. Dieses cut
wurde also anhand von Entwuerfen des Standards
implementiert. Zweieinhalb Jahre Arbeit war immerhin schon in
den Standardisierungsprozess geflossen; bis zur
Fertigstellung sollte es noch weitere zwei Jahre dauern.

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
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 bereits
abdeckten. Ein Argument fuer cut ist 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.

Die urspruengliche Variante (ohne -b) taucht 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.


Beschreibungen

Interessant ist ein Vergleich der Kurzbeschreibungen von cut,
wie sie sich in der Titelzeile von Manpages oder manchmal auch
am Anfang der Quellcodedatei finden.

Die folgende Liste ist grob nach Zeit geordnet und nach
Abstammung gruppiert:


System III	cut out selected fields of each line of a file
System III (src)	cut and paste columns of a table (projection of a relation)
System V	cut out selected fields of each line of a file
HP-UX		cut out (extract) selected fields of each line of a file

4.3BSD-UWisc (src)	cut and paste columns of a table (projection of a relation)
4.3BSD-Reno	select portions of each line of a file
NetBSD		select portions of each line of a file
FreeBSD 1.0	select portions of each line of a file
FreeBSD 7.0	cut out selected portions of each line of a file
SunOS 4.1.3	remove selected fields from each line of a file
SunOS 5.5.1	cut out selected fields of each line of a file

POSIX		cut out selected fields of each line of a file

GNU coreutils	remove sections from each line of files

Minix		select out columns of a file

Version 8 Unix	rearrange columns of data
``Unix Reader''	rearrange columns of text


Die zwei mit ``(src)'' markierten Beschreibungen sind aus
dem Quellcode entnommen, und verdeutlichen den Codetransfer.
POSIX ist ein Set von Standards, keine Implementierung. Der
``Unix Reader'' ist ein rueckblickendes Textdokument von
Doug McIlroy, das das Auftreten von Tools in der Geschichte
des Research Unix zum Thema hat. Alle uebrigen Beschreibungen
entstammen den Manpages.

Zumeist ist mit der Zeit die POSIX-Beschreibung uebernommen
worden, wie beispielsweise bei FreeBSD zu sehen.
[ https://svnweb.freebsd.org/base?view=revision&revision=167101

Interessant ist, dass die GNU coreutils unveraendert vom
Entfernen von Teilen der Eingabe sprechen, wohingegen die
Kommandozeilenangabe klar ein Auswaehlen darstellt. Die
Worte ``cut out'' sind vielleicht auch nicht klar genug.
HP-UX hat sie deshalb praezisiert.

Auch beim Begriff, was denn nun selektiert wird, ist man sich
uneins. Die einen reden von Feldern (POSIX), andere von
Abschnitten bzw. Teilen (BSD) und wieder andere von Spalten
(Research Unix). Ironischerweise leistet sich gerade Version
8 Unix, das eigentlich um eine sehr treffende Weltsicht
bemueht ist, mit ``rearrange columns of data'' die
unzutreffendste der Beschreibungen.



Codevergleich




B-) wc -lc cut.c* | sort -n
  123  2966 cut.c__system_iii.1980-04-11
  125  3038 cut.c__4.3bsd-uwisc.1986-11-07
  256  5715 cut.c__4.3bsd-reno.1990-06-25
  270  6545 cut.c__netbsd.1993-03-21
  296  6920 cut.c__freebsd.1994-05-27
  306  7500 cut.c__netbsd.2014-02-03	*
  479 10961 cut.c__freebsd.2012-11-24	*
  586 14175 cut.c__gnu.1992-11-08	*
  830 23167 cut.c__gnu.2015-05-01	*
 3271 80987 total

B-) c_count cut.c* | sort -n
Total:
116 cut.c__system_iii.1980-04-11
118 cut.c__4.3bsd-uwisc.1986-11-07
200 cut.c__4.3bsd-reno.1990-06-25
200 cut.c__netbsd.1993-03-21
224 cut.c__freebsd.1994-05-27
232 cut.c__netbsd.2014-02-03	*
382 cut.c__gnu.1992-11-08	*
391 cut.c__freebsd.2012-11-24	*
588 cut.c__gnu.2015-05-01	*
2451

(* == version hat -b)




cut(1) in Version 8 Unix
``In data base parlance, it projects a relation.''



Autoreninfo

Markus Schnalke interessiert sich fuer die Hintergruende
von Unix und seinen Werkzeugen. Fuer die Erarbeitung dieses
Textes wurde er regelrecht zum Historiker.


Lizenz
CC0 (und kann damit auch unter CC BY-SA 4.0 Unported
veroeffentlicht werden)