freeX: Konsolen-Farben

Die ausschließlichen Vertriebsrechte an diesem Artikel liegen beim Computer- & Literaturverlag (C&L). Der Artikel darf nicht kopiert oder gar erneut in einer Zeitschrift oder einem Buch veröffentlicht werden ohne vorherige Erlaubnis von C&L. Der Verlag gestattet freundlicherweise die Veröffentlichung auf diesen Seiten. Wer öfter auf diesen Hinweis trifft, sollte sich überlegen, die Zeitschrift freeX zu abonnieren.

Konsolen-Farben

 

Früher waren Unix- und GNU/Linux-Systeme bekannt für ein einfarbiges Text-Terminal. Grafische Terminals waren auch noch nicht so farbenfroh gestaltet wie heute. Mit fortgeschrittener Entwicklung hielten Farben auch in Terminals unter GNU/Linux Einzug. Wie sie in eigenen Programmen verwendet werden, beschreibt dieser Artikel.

 

1. Anpassung der Farben für »ls«
2. Einstellung der Farben
3. Farbiger Mail-Client
4. Farben in Shell-Skripten
5. Datenströme einfärben
6. Farben und Ausgabe-Umleitung
7. Farben in Perl
8. Farben in Python
9. Farben in C

Vor einem Jahrzehnt haben die Entwickler der Distribution Slackware quasi Farbe auf die Textkonsole gebracht. Sie haben das Programmpaket »fileutils«, in dem das Programm »/bin/ls« enthalten ist, derart modifiziert, daß Verzeichniseinträge farbig dargestellt werden können. Diese Erweiterung wurde in das Paket aufgenommen und als Folge gehört ein farbiges »ls« heutzutage zum Standard unter GNU/Linux.

Wenn eine farbige Darstellung gewünscht wird, stellt »ls« den Dateinamen abhängig vom Datei-Suffix andersfarbig dar. Auf den ersten Blick mag das zwar verwirrend sein, wenn eine solche Darstellung ungewohnt ist. Doch wenn man sich daran gewöhnt und die Farben den eigenen Bedürfnissen angepaßt hat, helfen sie beim schnellen Erkennen der Informationen auf einen Blick.

Gesteuert wird das Verhalten von »ls« durch die Umgebungsvariable »LS_COLORS«. In dieser ist definiert, welche Farbe welchen Dateitypen und Suffixen zugeordnet ist. Damit ist es jedoch noch nicht getan, da »ls« zudem angewiesen werden muß, die Farbeinstellungen auch zu verwenden.

Das geschieht über den Parameter »--color=auto«, der bei vielen Distributionen bereits über eine Alias-Definition für die Bash voreingestellt ist. Falls das noch nicht der Fall ist hilft folgender Eintrag in einer der Dateien »/etc/profile« bzw. »~/.bash_profile« und »~/.bashrc«:

   alias ls='ls --color=auto'

Wenn mit dieser Einstellung die Variable »LS_COLORS« nicht definiert ist, verwendet »ls« die Voreinstellungen der Autoren.

Anpassung der Farben für »ls«

Die Umgebungsvariable »LS_COLORS« steuert zwar das Verhalten von »ls«, sie muß jedoch nicht manuell justiert werden, um die Einstellungen zu ändern. Der Inhalt sieht ungefähr wie folgt aus:

   no=00:fi=00:so=40;33:bd=40;33;01:ex=01;32:*.tar=01;31:*.tif=01;35:

Daß eine derartige Liste schlecht zu warten ist, versteht sich von selbst. Sie wird üblicherweise vom Programm »dircolors« erzeugt, so daß die Ausgabe dieses Programms nur angepaßt werden muß.

Wird »dircolors« ohne Argumente aufgerufen, erzeugt das Programm Shellcode, mit dem die benötigte Umgebungsvariable passend gesetzt wird. Dabei werden Anweisungen für eine Bourne Shell (z.B. »bash«) mit »-b« und für eine C-Shell (z.B. »tcsh«) mit »-c« erzeugt. Das Programm ist somit für die verschiedenen Shells gleichermaßen geeignet.

Da das Programm die Variable jedoch nicht selbst setzen kann, wird der Aufruf in einer Bourne Shell in »eval« eingefaßt. Mit den folgenden Zeilen in der Datei »~/.bashrc« ist somit gewährleistet, daß in einem normalen Terminal die Anzeige von Dateinamen Farben verwendet. Wenn diese Datei nicht von ».bash_profile« eingelesen wird, muß der Code dort dupliziert werden.

   eval `dircolors -b`
   alias ls='ls --color=auto'

So verwendet »dircolors« jedoch lediglich die vom Autor voreingestellten Farbdefinitionen. Obwohl eine standardisierte Konfigurationsdatei nicht vorgesehen ist, kann beim Aufruf eine Konfigurationsdatei angegeben werden, die anstelle der Voreinstellung verwendet wird. Mit dem Befehl

   dircolors -p > ~/.dircolors

wird erst einmal die vom Autor vorgegebene Konfiguration in einer Datei gespeichert. Diese wird anschließend nach Belieben verändert. Anstelle des oben genannten Befehls muß jedoch jetzt die neue Konfigurationsdatei angegeben werden:

   eval $(dircolors -b ~/.dircolors)

Diese Datei besteht aus drei logischen Abschnitten, deren Inhalte jedoch beliebig angeordnet werden dürfen. Zur generellen Aktivierung werden die »TERM«-Einträge benötigt. Mit diesen wird festgelegt, für welche Terminals Farbeinstellungen überhaupt gesetzt werden sollen.

In der Voreinstellung werden diverse aktuelle und veraltete »TERM«-Einstellungen aufgezählt, die unter GNU/Linux üblich sind oder waren, so daß Farben automatisch für die meisten Linux-Terminals funktionieren sollten. Wenn Farbe auf einem Terminal gewünscht wird, »dircolors« jedoch keine Farbinformationen für »ls« generiert, fehlt wahrscheinlich eine »TERM«-Anweisung. In dem Fall wird einfach der Inhalt der Umgebungsvariable »TERM« (»echo $TERM« im Terminal eingeben) in die Konfigurationsdatei geschrieben.

Einstellung der Farben

Die Farben werden in Form von Zahlenwerten angegeben (siehe Tabelle). Dabei werden bis zu vier Werte erwartet, die durch ein Semikolon voneinander getrennt werden. Mit den Zahlen werden spezielle Attribute (fett, blinkend, unterstrichen etc.), sowie die Farbe für den Vorder- und Hintergrund festgelegt. Um z.B. die Namen von ausführbare Dateien in leuchtendem grün darzustellen, verwendet man »01;32« als Farbe.

Eine Besonderheit betrifft gelb bzw. braun. Leuchtend helles braun wird nämlich als leuchtendes gelb dargestellt. Normales braun hingegen erscheint wie erwartet braun. Die Farbe ändert sich in Abhängigkeit mit dem Attribut fett.

Terminal-Farben für »ls« bzw. »dircolors«
00Normale Video-Darstellung (z.B. weiß auf schwarz~)
01Attribut fett
04Attribut unterstrichen
05Attribut blinkend
07Vorder- und Hintergrund vertauscht
22Normale Intensität wiederherstellen
30Vordergrund schwarz
31Vordergrund rot
32Vordergrund grün
33Vordergrund braun (bzw. gelb für fett)
34Vordergrund blau
35Vordergrund magenta
36Vordergrund cyan
37Vordregrund weiß
40Hintergrund schwarz
41Hintergrund rot
42Hintergrund grün
43Hintergrund braun
44Hintergrund blau
45Hintergrund magenta
46Hintergrund cyan
47Hintergrund weiß
49Voreingestellter Hintergrund

Der zweite logische Block in einer Konfigurationsdatei für »dircolors«, beschreibt die zu verwendenden Farben für verschiedene Spezialdateien. Im dritten Teil werden die Farben für Dateien nach speziellen Mustern festgelegt.

Jede Kombination von Dateityp und Farbe wird in einer eigenen Zeile beschrieben. Diese besteht aus dem Typen, beliebig vielen Leerzeichen und den Farbangaben. Kommentare werden mit dem unter Unix üblichen Kommentarzeichen »#« eingeleitet und dürfen auch mitten in einer Zeile beginnen.

Speziellen Dateitypen
NORMALNormaler Text, der nicht durch eine andere Beschreibung abgedeckt ist (insbesondere der Text links vom Dateinamen)
FILENormale Datei, die von keinem der angegebenen Muster abgedeckt wird
EXECAusführbare Dateien
LINKSymbolischer Link
FIFOFIFOs (benannte Pipes)
SOCKSocket
DOORVerbindung zu einem Programm mittels Inter Process Communication (IPC). Nur unter Solaris vorhanden.
DIRVerzeichnis-Name
BLKBlock-orientiertes Gerät (üblicherweise in »/dev«, z.B. »/dev/sda1«)
CHRZeichen-orientiertes Gerät (üblicherweise in »/dev«, z.B. »/dev/ttyS0«)
ORPHANLoses Ende eines symbolischen Links, wenn die Zieldatei nicht existiert

Um Verzeichnisse leuchtend gelb und ausführbare Dateien leuchtend grün darzustellen, werden die folgenden Zeilen in der Konfigurationsdatei geschrieben:

   EXEC 01;32
   DIR  01;33

Farbiger Mail-Client

Farben haben nicht nur bei der Anzeige von Dateien Einzug gehalten, sondern auch in Text-orientierten Programmen. Mutt ist zum Beispiel ein weit verbreitetes Mail-Programm, das in vielen Distributionen von Hause aus eine farbige Oberfläche bietet. Diese kann sogar bis ins kleinste Detail konfiguriert werden.

Dabei werden die Farben jedoch nicht mehr als Zahlen angegeben, sondern es werden bequem englische Bezeichnungen (»red«, »green« etc.) verwendet. Um zum Beispiel den Balken, der die aktuelle Mail hervorhebt, rot zu färben und dabei den Text in hellgelb darzustellen, schreibt man diese Zeile in die Datei »~/.muttrc«.

   color   indicator   brightyellow    red

Dieses soll lediglich als ein Beispiel für Mutt gelten. Das Programm bietet eine Vielzahl von Einstellungen, inklusive der Verwendung von regulären Ausdrücken beim Anzeigen von Mail. Alle Möglichkeiten hier zu beschreiben, würden den Rahmen in diesem Artikel sprengen. Daher sei an dieser Stelle auf die ausführliche Dokumentation verwiesen.

Farben in Shell-Skripten

Die Verwendung von Farben in Text-Terminals ist keine Schwarze Magie und kann daher auch leicht in eigene Programme integriert werden. Die Grundlagen dazu sind unter anderem in der Manpage »console_codes(4)« im Abschnitt "ECMA-48 Set Graphics Rendition" beschrieben. Die dort angegebenen numerischen Codes sind die gleichen wie in der nebenstehenden Tabelle.

Wichtig ist für die Programmierung die Beschreibung, wie Farben in einem farb-tauglichen Text-Terminal eingestellt werden. Dazu werden neben dem Farbcode drei Zeichen benötigt: »ESC« »[«, dann der bzw. die Zahlencodes, und anschließend ein »m«. Sollen zwei oder drei Codes kombiniert werden, so wird der gesamte Block mehrfach ausgegeben oder die Zahlenwerte werden wie in der Konfigurationsdatei oben durch ein Semikolon voneinander getrennt.

Wenn eine derartige Zeichenkette vom Terminal-Treiber erkannt wird, gibt dieser die Zeichen nicht direkt wieder aus, sondern behandelt sie als besonderen Befehl. In diesem Fall werden die zusätzlichen Attribute des Terminals ab der aktuellen Cursor-Position wie in der Zeichenkette angegeben umgestellt.

Wichtig ist in diesem Zusammenhang zu bemerken, daß die Farbeinstellungen explizit zurückgesetzt werden müssen, da sie nicht nur für eine Zeile oder einen »echo«- bzw. »printf«-Befehl gültig sind. Wenn wieder die normale Darstellung des Terminals verwendet werden soll, wird daher mit »[0m« auf die normalen Farben zurückgeschaltet.

Das Zeichen »ESC« kann auf unterschiedliche Arten eingegeben werden. In der ASCII-Tabelle steht dieses Zeichen an Position 27, oktal also 033. Dargestellt wird es als »^[«. Im Emacs wird ESC z.B. über »Ctrl-q« »ESC«, »Ctrl-q« »Ctrl-[« oder »Ctrl-q« »0« »3« »3« »Enter« eingegeben. In einem VI und in der Bash gibt man »Ctrl-v« »ESC« oder »Ctrl-v« »Ctrl-[« ein.

Das Zeichen wird so jedoch nur dann benötigt, wenn zur Ausgabe der Texte kein Programm (bzw. keine in der Shell eingebaute Funktion) verwendet wird, das Zeichen in oktaler Darstellung interpretiert und konvertiert. Das ist z.B. bei »echo« der Bash der Fall, wenn nicht der Parameter »-e« angegeben wird. »printf« hingegen ist ein eigenständiges Programm, das auch Zeichen in oktaler Darstellung interpretiert.

Die Implementierung von »echo« in anderen Shells unterstützt nicht zwingenderweise den Parameter »-e«. Somit schreiben die drei folgenden Befehle einen Text hell erleuchtet dar.

   echo "^[[1mHallo^[[0m freeX"
   echo -e "\033[1mHallo\033[0m freeX"
   printf "\033[1mHallo\033[0m freeX\n"

Wenn der Text statt leuchtend weiß in einem leuchtenden gelb erscheinen soll, wird zur bisherigen Farb-Einstellung eine weitere benötigt. Da zwei Einstellungen benötigt werden, kann dieses wie oben beschrieben auf zwei Arten erfolgen. Die beiden folgenden Befehle schreiben den Text in der gewünschten Farbe auf das Terminal:

   echo -e "\033[1m\033[33mHallo\033[0m freeX"
   echo -e "\033[1;33mHallo\033[0m freeX"

Datenströme einfärben

Natürlich können auf diese Art und Weise auch Datenströme ganz oder teilweise eingefärbt werden, die im Programm lediglich verarbeitet oder gefiltert werden. Farbinformationen können z.B. mit Hilfe von »sed« in den den Datenstrom eingespeist werden, so daß ein Teil der Daten farbig dargestellt wird.

So ist es z.B. ein leichtes, die textuelle Beschreibung zu einem Debian-Paket in der Ausgabe von »apt-cache« grün einzufärben. Die Beschreibung steht in einem speziellen Abschnitt, dessen Name als Schlüsselwort verwendet wird. Das folgende Fragment stellt zudem den längeren Text normal dar, während die einzeilige Beschreibung sogar fett ausgegeben wird.

   apt-cache show $1 | sed "s/^Description: \(.*\)/Description: ^[[1;32m\1^[[22m/"
   echo -n -e "\033[0m"

Die als »^[« dargestellten Zeichen werden dabei wie oben beschrieben eingegeben. Dieser Befehl kann genauso auch in einer Shell eingegeben und muß nicht notwendigerweise in eine Skript-Datei geschrieben werden.

Farben und Ausgabe-Umleitung

Ein kleines Problem tritt jedoch dann auf, wenn die Ausgabe des Programms, das Farben verwendet, in Dateien oder weitere Filter umgeleitet wird. Bisher würde das nämlich bedeuten, daß die Sonderzeichen weiterhin in der Ausgabe auftauchen würden, was unter Umständen nicht gewünscht ist, insbesondere bei Dateien.

In einem Shell-Skript ist das jedoch kein Problem, denn dort kann sehr einfach überprüft werden, ob »stdout« ein Terminal ist oder nicht. Der Test »-t deskriptor« prüft, ob der angegebene Deskriptor ein echtes Terminal ist und liefert wahr oder falsch zurück. Die Standard-Ausgabe eines Programms ist üblicherweise mit dem Datei-Deskriptor 1 verbunden, so daß das folgende Fragment in einem Programm hilft:

   if [ -t 1 ]
   then
   else
   fi

Um die Verwendung von Farben im Programm abhängig von einem echten Terminal zu machen, werden die Farbcodes am besten in Variablen gespeichert. Im zweiten Fall der obigen Verzweigung wären das dann Variablen ohne Wert und nur im ersten Fall würden dort tatsächlich Farbwerte stehen.


   ESC="^["
   if [ -t 1 ]
   then
      red="${ESC}[31m"
      lightgreen="${ESC}[33;1m"
      normal="${ESC}[0m"
   else
      red=
      lightgreen=
      normal=
   fi

In diesem Beispiel wurde dem Zeichen für ESC bewußt eine eigene Variable spendiert. So vermeidet man nicht nur das umständliche Eingeben dieses Kontrollzeichens, sondern verhindert auch die unbeabsichtige Interpretation im Terminal. Ansonsten ist es möglich, daß die Farbe des Terminals unbeabsichtig geändert wird, wenn das Programm mittels »cat« auf diesem ausgegeben wird.

Farben in Perl

Das bisher für eine Bourne Shell gesagte, gilt genauso auch für Perl-Programme. Dort wird der Test, ob die Ausgabe mit einem richtigen Terminal verbunden ist, auf die gleiche Art und Weise durchgeführt. Allerdings darf in dieser Sprache auch direct »STDOUT« geschrieben werden anstelle des numerischen Datei-Deskriptors. Ein einfaches Beispielprogramm sieht dann wie folgt aus:

   if (-t STDOUT) {
      print "^[[32;1mtty^[[0m\n";
   } else {
      print "notty\n";
   }

Farben in Python

In Python können Farbattribute für Terminalausgaben genauso verwendet werden. Die Abfrage, ob ein echtes Terminal vorliegt oder etwas anderes, sieht jedoch etwas anders aus. Dazu muß das Objekt »stdout« oder zumindest das Modul »sys« importiert werden. Das Objekt besitzt eine Methode »isatty«, die wahr oder falsch zurückliefert, abhängig davon, ob ein echtes Terminal vorliegt oder nicht. Das gleiche Beispiel sieht daher in Python implementiert wie folgt aus:

   from sys import stdout

   if stdout.isatty():
       print "^[[32;1mtty^[[0m"
   else:
      print "notty"

Farben in C

Wer kein text-orientiertes Widget-Set wie slang oder whiptail für einfache C-Programme verwenden möchte, darf die Farbdefinitionen genauso wie in den bisher vorgestellten Skript-Sprachen auch in C einsetzen. Die Terminal-Abfrage gestaltet sich jedoch etwas aufwendiger, funktioniert aber im Prinzip genauso wie in Python. Das gleiche Programm sieht in C implementiert dann so aus:


   int main (int argc, char **argv[])
   {
     if (isatty (fileno (stdout)))
       printf ("^[[32;1mtty^[[0m\n");
     else
      printf ("notty\n");
     return 0;
   }

Joey Schulze
Quelle: freeX 3/00