Skip to content

Colorer une sortie dans un terminal : highlight, pygmentize et ccze

highlight et pygmentize servent à colorer du code source, ccze à colorer des logs.

Affichage de la sortie de cat, highlight et pygmentize

Pour utiliser ces outils, voici les paquets à installer sur une distribution Debian ou dérivée :

commande paquet
highlight highlight
pygmentize python-pygments ou python3-pygments
ccze ccze

highlight et pygmentize

De nombreux langages disponibles

La liste des langages disponibles pour les deux outils est longue comme un jour sans compilation :
highlight colore 159 langages selon sa documentation.
pygmentize en colore 235 d’après un grep Lexer$ sur le texte de la page listant les lexeurs disponibles.

Plutôt que de tous les lister, voici un comparatif sur les 20 langages ayant le plus de lignes de code dans Jessie (la nouvelle version stable de Debian).

  1. C : les deux
  2. C++ : les deux
  3. Java : les deux
  4. XML : les deux
  5. sh : les deux
  6. Python : les deux. pygmentize a plusieurs lexeurs (python 2, python3, sortie console et la pile d’erreurs).
  7. Perl : les deux
  8. Lisp : les deux
  9. Asm : les deux. highlight colore aussi l’assembleur PowerPC.
  10. Fortran : highlight traite spécifiquement fortran77, pas pygmentize (qui gère la version 90).
  11. C# : les deux
  12. PHP : les deux
  13. Fortran90 : les deux
  14. Pascal : les deux. pygmentize nécessite d’utiliser Delphi lexer, avec option spécifique.
  15. Makefile : highlight (make, QMake), pygmentize (Makefile, CMake)
  16. Ruby : les deux. pygmentize colore le langage mais aussi la sortie console.
  17. SQL : highlight (MSSQL, SPIN SQL, PL/SQL, Sybase), pygmentize (MySQL, PgSQL, PL/PgSQL, console Postgres, SQL, console Sqlite)
  18. ML : les deux (Standard ML ainsi qu’Ocaml)
  19. Tcl : les deux

À cette liste, voici le comparatif sur les 20 premiers langages selon l’indice TIOBE en mars 2015 (sans juger de l’intérêt profond du classement en lui-même, ou son absence) :

  1. C : cf. liste précédente
  2. Java : cf. liste précédente
  3. Objective-C : les deux
  4. C++ : cf. liste précédente
  5. C# : cf. liste précédente
  6. PHP : cf. liste précédente
  7. JavaScript : les deux
  8. Python : cf. liste précédente
  9. Visual Basic .NET : ? (je ne connais pas les environnements Microsoft donc j’ai tout mis à la ligne suivante)
  10. Visual Basic : highlight colore les fichiers avec les extensions de fichiers .bas, .basic, .bi et .vbs. pygmentize colore ceux en .vb et .bas.
  11. F# : les deux
  12. Perl : cf. liste précédente
  13. Delphi/Object Pascal : pyg
  14. Transact-SQL : aucun des deux
  15. Pascal : cf. liste précédente
  16. ABAP : les deux
  17. PL/SQL : highlight uniquement
  18. Ruby : cf. liste précédente
  19. MATLAB : les deux. pygmentize colore le langage et la sortie console.
  20. R : les deux. pygmentize colore le langage (avec SLexer, ce n’est pas intuitif), la sortie console et la documentation.

pygmentize et highlight permettent la coloration syntaxique de nombreux autres langages comme Applescript, Awk, Bbcode, Clojure, Haxe, Lua et bien d’autres.

Les fichiers de configuration d’Apache sont colorés par les deux outils. pygmentize colore aussi la configuration de Lighttpd et Nginx mais aussi d’autres fichiers de configuration comme Docker ou CFEngine.

Contrairement à highlight, pygmentize permet aussi de colorer des logs IRC, les fichiers CMake ou du code spécifique aux moteurs de template (django, smarty, mako, genshi, erb).

hightlight colore COBOL ou graphviz, pas pygmentize.

Facile à utiliser

Les deux outils sont triviaux à installer. L’usage est facile aussi car ils déterminent le lexeur à utiliser en fonction de l’extension du fichier. Il est possible de forcer l’utilisation d’un lexeur (utile si les données viennent d’un pipe par exemple).

Par contre (et par défaut), highlight sort la coloration en html et non pour la console. Ce qui oblige à préciser la sortie terminal souhaitée. Il y en a deux possibles : ansi (16 couleurs) et term256 (256 couleurs). Ansi serait-il à réserver aux plus nostalgiques ? Ce choix cornélien s’impose aussi avec pygmentize (sortie par défaut contre console256).
Dans les faits, les différences ont peu d’intérêt.

highlight et pygmentize, période ansi et période 256 couleurs

Colorer de nouveaux langages

Les deux outils permettent d’ajouter de nouveaux lexeurs :
– en Lua pour highlight
– en Python pour pygmentize (qui est lui-même écrit en Python)

Autres usages

highlight et pygmentize permettent d’avoir d’autres sorties :

sorties highlight pygmentize
HTML oui oui
XHTML oui non
SVG oui oui
RTF oui oui
ODT oui non
Images bitmap non oui (bmp, gif, jpeg et png)

highlight est compatible avec source-highlight du projet GNU (outil que je n’ai jamais testé).

Que choisir ?

Si vous avez besoin d’un langage qui est disponible que sur l’un des deux outils, choisissez celui-là.
Si vous comptez écrire des greffons pour ajouter des langages, choisissez si vous préférez écrire en Lua ou en Python.
Si les deux règles précédentes ne permettent pas d’emporter la décision, je conseillerai plutôt pygmentize qui a plus de langages et qui gère des trucs plus récents (les moteurs de template par exemple). Évidemment, si c’est pour maintenir du code COBOL sur une base logicielle de 15 ans d’âge, ça ne sera pas très déterminant non plus…

ccze

ccze n’est pas concurrent des deux outils précédents car il colore des journaux, pas du code.

Affichage de la sortie de cat et ccze

Les remarques et usages de http://www.quennec.fr/gnulinux/utilisation/afficher-les-logs-en-couleur sur ccze sont valides. Cependant j’ai dû activer le mode ansi (avec -A ou --raw-ansi ou bien -m ansi ou encore --mode ansi) lors de mes tests, sinon il n’y avait aucune sortie dans le terminal.

Les journaux d’Apache, Exim, Postfix, syslog sont colorés par ccze. Pour la liste complète, man ccze.

Il est aussi possible d’ajouter de nouveaux type de journaux. Par contre, il faudra les écrire en C (cf. man ccze-plugin).

Fin : références, versions des logiciels

Les statistiques Debian concernant les langages sont issues de http://sources.debian.net/stats/. Pour en savoir plus, voir aussi http://sources.debian.net/doc/ (en particulier « Debsources: Live and Historical Views on Macro-Level »).

La page des lexers de pygmentize est /usr/share/doc/python-pygments-doc/html/docs/lexers.html sur Jessie (en supposant que python-pygments-doc est installé). L’emplacement était /usr/share/doc/python-pygments/lexers.html sur Wheezy (la version stable précédente) et était directement incluse dans le paquet python-pygments.

Les versions utilisées pour l’article :

stephane@foehn:~$ pygmentize -V
Pygments version 2.0.1, (c) 2006-2014 by Georg Brandl.
stephane@foehn:~$ highlight --version

 highlight version 3.18
 Copyright (C) 2002-2013 Andre Simon <andre.simon1 at gmx.de>

 Argparser class
 Copyright (C) 2006-2008 Antonio Diaz Diaz <ant_diaz at teleline.es>

 Artistic Style Classes (2.04)
 Copyright (C) 2006-2013 by Jim Pattee <jimp03 at email.com>
 Copyright (C) 1998-2002 by Tal Davidson

 Diluculum Lua wrapper (1.0)
 Copyright (C) 2005-2013 by Leandro Motta Barros

 xterm 256 color matching functions
 Copyright (C) 2006 Wolfgang Frisch <wf at frexx.de>

 This software is released under the terms of the GNU General Public License.
 For more information about these matters, see the file named COPYING.

stephane@foehn:~$ ccze --version
ccze 0.2.1

Key Signing Assistant (concept)

Dans les allées de la DebConf14, j’ai discuté avec Franklin de l’intérêt pour un développeur d’utiliser son téléphone portable lors d’une key signing party.

Les schémas sont un brouillon d’une utilisation possible du téléphone. L’objectif n’est pas de remplacer la rencontre réelle ou la validation mais juste d’aider à l’échange et validation des clefs.

Actuellement, ce n’est qu’un concept ; rien n’est implémenté.

Le principe général est d’utiliser le téléphone comme un terminal pour l’échange et la validation. Les données partent et reviennent sur la station de travail du développeur par l’intermédiaire d’un serveur web.

  • Le téléphone portable considéré doit être un smartphone ;
  • La seule autorisation à donner pour le téléphone est l’accès à internet ;
  • On considère que les échanges réseau sont fait en https. Je ne pense pas que ce soit indispensable mais il n’y a aucune raison de s’en priver.

Avant la key signing party

Le développeur dispose d’un téléphone sur lequel l’application est installée.
Le processus pour installer ses propres informations est le suivant :

Avant la key signing party

Pendant la key signing party

Le processus est à reproduire pour chaque participant.

Pendant la key signing party

Après la key signing party

Une fois rentré chez lui, le développeur récupère l’ensemble de ses validations sur sa machine de travail :

Après la key signing party

Qu’en pensez-vous ?

Source des schémas

Schémas réalisés avec Inkscape, à partir d’icônes Tango et Gnome-Tango.
Les fichiers svg et png sont disponibles dans le répertoire http://stephane.yaal.fr/ksa/.

Écrire des tests automatisés (ou pas)

Les tests automatisés sont des tests qui sont exécutés par la machine régulièrement. Par example, à chaque fois qu’un commit est réalisé dans un système de gestion de version (comme subversion, mercurial, git, voire CVS pour les plus nostalgiques). L’utilisation de tests automatisés permet d’espérer des gains de temps et de sérénité.

L’article vise à montrer les avantages et les limites des tests automatisés ainsi que des pistes pour que des personnes (ou équipes) sans expérience dans le domaine puissent s’y mettre.

I. Pourquoi ne PAS faire de tests automatisés

Il existe des cas où ne pas avoir de tests automatisés peut être un choix pertinent.

1. Nouveauté

Lorsque l’on découvre quelque chose d’autre de nouveau, le besoin d’expérimenter et de comprendre le fonctionnement est prioritaire. Se contraindre à ajouter des tests en même temps peut gêner l’expérimentation. Dans ce cas, il est préférable de ne pas en faire pour se concentrer sur la nouveauté. Il est plus simple de n’apprendre qu’une chose à la fois donc ce n’est pas la peine d’avoir à apprendre une nouveauté et d’apprendre à tester cette nouveauté en même temps.
Ce cas s’applique lors de l’utilisation d’un nouveau langage ou d’un nouveau framework par exemple.

2. Besoin très simple

Si le besoin est très simple, il est possible que ne pas avoir de tests soit plus rapide car faire les tests à la main ira plus vite (partie gauche de la droite rouge sur le schéma).

Rendements de l'utilisation de tests

Plus le produit est complexe, plus il devient fastidieux de retester toutes les fonctionnalités et le temps passé devient très important (partie droite de la droite rouge sur le schéma). Dans les faits, seules les dernières modifications sont testées et le reste du logiciel est supposé ne pas être influencé par les modifications. C’est vrai la plupart du temps mais cela laisse la porte ouverte à des régressions.

3. Code jetable

Dans le cas d’un programme qui a un usage unique (extraction de données particulières, migration d’un schéma de base de données, traitement d’un cas client particulier), avoir des cas à vérifier peut être une solution plus rapide et aussi fiable que des tests automatisés.

Par contre, si l’on prévoit de garder le script pour le réutiliser plus tard dans des conditions similaires, le même effet va se reproduire : avoir des tests sera plus efficace à long terme.

Le problème n’est pas d’écrire du code jetable, c’est de ne pas le jeter.

Pour tout le reste, il y a probablement des tests qui vous rendraient service.

II. Beaucoup de tests possibles

Il existe de nombreux types de tests (tests unitaires, tests d’intégration, tests de performance, …), chacun d’entre eux répondant à des besoins différents. Certains articles portant sur les tests les listent de manière exhaustive, donnant une impression de travail à fournir gigantesque.

Pourtant, pour bénéficier des avantages des tests automatisés :

  • il n’y a pas besoin de tous les faire ;
  • il n’y a pas besoin de tout tester.

En ayant l’impression que la tâche est énorme, il y a un risque de procrastination. Le coût de mise en place sera considéré comme très élevé et sera continuellement repoussé. Les tests ne seront donc jamais fait.

Il me semble préférable de commencer par des tests faciles (un algorithme de tri par exemple) ou là où le besoin se fait sentir. Sur du code préexistant, il peut être plus simple de commencer par des tests vérifiant un fonctionnement assez général (par exemple, à une requête web, le serveur renvoie une page avec un code 200).
Une fois le mouvement initié, il sera plus aisé d’augmenter la couverture au fur et à mesure. De même, on pourra augmenter la complexité des éléments à tester (comme vérifier les données enregistrées dans une base de données, l’interfaçage avec une API externe, etc.). Il existe des solutions classiques pour ces cas mais ne pas commencer par là permet d’esquiver ces problèmes au début.

Le plus probable est de débuter avec des tests unitaires mais ce n’est pas une obligation. Le plus important étant d’avoir des tests réellement automatisés pour pouvoir bénéficier des avantages qu’ils procurent, ce qui devrait aider à les maintenir et à améliorer la couverture du code.

III. Pré-requis

Évidemment, il faut pouvoir exécuter les tests et l’application hors de la production, au mininum soit sur la machine locale des développeurs, soit dans un environnement d’intégration.

Si les développement sont validés directement en production, la priorité est d’avoir au moins un environnement de développement spécifique, pas d’écrire des tests automatisés. L’écriture des tests est secondaire et sera réalisée par la suite.

IV. Des bogues subsisteront

Les tests ne garantissent pas l’inexistence d’anomalies. Pour cela, il faudrait utiliser des méthodes formelles mais le coût de mise au point est tellement coûteux…

Les tests ne protègent que :

  • des erreurs de syntaxe des fichiers inclus (même si le code lui-même est non testé) ;
  • du non-respect des assertions qu’ils incluent.

Les tests sont donc une solution imparfaite mais :

  • plus la couverture est élevé et plus on est sûr de couvrir de fonctionnalités et de cas particuliers ;
  • c’est une garantie contre les régressions futures ;
  • le fait qu’ils soient automatisés permet d’avoir facilement une idée de l’état du code à n’importe quel moment. Il permet donc de détecter immédiatement lorsque une régression survient.

Avoir des tests automatisés est donc une solution préférable à aucun test. Les gains obtenus par les tests automatisés surpassent les inconvénients dans le cas général.

V. TDD ?

Faire du développement dirigé par les tests (TDD, pour Test Driven Development) est souvent cité en même temps que l’importance de faire des tests. Au-delà des avantages de TTD, les aficionados affirment aussi que c’est plus simple une fois que l’on y on est habitué. Pourquoi ?

1. Processus de développement avec TDD

Le processus de développement est itératif (comme sans TDD). La boucle commence avec le noeud en vert. L’étape d’amélioration du code (noeud refacto dans le schéma) doit être faite si le nécessaire. Les autres étapes sont toutes obligatoires  :

Processus de développement avec TDD

2. Processus de développement sans TDD

Pour obtenir la même garantie, voici le processus à suivre :
Processus de développement sans TDD

L’étape de désactivation du code pour vérifier que le test ne passe plus est nécessaire car sans elle, il n’est pas possible de valider que le test vérifie correctement le code. Cette désactivation est généralement réalisable trivialement en commentant le code ajouté.

Il est possible d’avoir des tests automatisés sans TDD :

  • si le développeur le fait selon le processus présenté ci-dessus ;
  • si ce sont des équipes différentes qui écrivent le code et ceux qui écrivent les tests.

Il me semble regrettable de ne pas en faire, mais il n’est pas nécessaire d’écrire ses premiers tests automatisés avec TDD : si c’est déjà une nouveauté, pas besoin d’en ajouter une deuxième.

Pour ceux qui voudraient un guide pratique en Python (principalement sur les tests unitaires mais les réflexions s’appliquent aux autres langages), en trois parties sur sametmax :
Partie 1, Partie 2, Partie 3

Annexe : Code source des graphiques

Le graphique a été créé avec la bibliothèque python matplotlib v.1.1.1 (paquet python-matplotlib dans Debian). Voici le script qui a permis de le produire :

# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

ax.plot(range(10), range(10)) #sans test
ax.text(7.5, 7, 'sans tests', style='italic', color="blue")

ax.plot([0, 9], [2, 5]) #avec test
ax.text(7.5, 4.1, 'avec tests', style='italic', color="green")

ax.plot([6, 6], [0, 9]) # début de la rentabilité des tests

ax.annotate(u"le code avec tests devient\nplus rapide à\ndévelopper/maintenir",
    (3, 3),
    xytext=(-110, +50),
    arrowprops={"arrowstyle": '->'},
    textcoords="offset points",
    bbox=dict(boxstyle="round", fc="0.8"),)

ax.annotate(u"début de la\nrentabilité",
    (6, 1.5), 
    xytext=(+40, +25), 
    arrowprops={"arrowstyle": '->', "connectionstyle": "angle,angleA=-90,angleB=180,rad=10"},
    textcoords="offset points",
    bbox=dict(boxstyle="round", fc="0.8"),)

plt.xlabel(u"Complexité")
plt.ylabel(u"Temps passé")

ax.spines["right"].set_visible(False)
ax.spines["top"].set_visible(False)
ax.tick_params(axis='both', which="both",
     bottom=False, top=False, right=False, left=False,
     labelbottom=False, labelleft=False)

plt.savefig("./rendements_tests.png")

Les graphes ont été réalisés avec dot (contenu dans le paquet graphviz dans Debian).
Avec TDD:
$ dot -Tpng tests_avec_tdd.gv -o tests_avec_tdd.png
Contenu du fichier tests_avec_tdd.gv

digraph G {
        "écriture du test" [color=darkgreen, fontcolor=darkgreen, shape=rectangle];
        "(refacto)" [color=darksalmon, style=filled, shape=polygon, sides=7];

        "écriture du test" -> "le test ne passe pas";
        "le test ne passe pas" -> "écriture du code";
        "écriture du code" -> "le test passe";
        "le test passe" -> "(refacto)";
        "(refacto)" -> "écriture du test";
}

Sans TDD:
$ dot -Tpng tests_sans_tdd.gv -o tests_sans_tdd.png
Contenu du fichier tests_sans_tdd.gv

digraph G {
        "écriture du code" [color=darkgreen, fontcolor=darkgreen, shape=rectangle];
        "(refacto)" [color=darksalmon, style=filled, shape=polygon, sides=7];

        "écriture du code" -> "le code fonctionne";
        "le code fonctionne" -> "écriture du test";
        "écriture du test" -> "le test passe";
        "le test passe" -> "désactivation du code";
        "désactivation du code" -> "le test ne passe plus";
        "le test ne passe plus" -> "réactivation du code";
        "réactivation du code" -> "(refacto)";
        "(refacto)" -> "écriture du code";
}

DebConf sur la planète

Cette année, la conférence Debian annuelle aura lieu à Portland, aux États-Unis. Comme l’année dernière, j’y participerai. :)

Participation à la conférence Debian

Cette conférence sera la quinzième du nom. Voici une carte des différentes DebConf (passées en rouge, la prochaine en blanc et celle de l’année prochaine en jaune).

debconf14_planet

Jusqu’ici les conférences ont eu lieu alternativement en Europe et en Amérique (du Nord, centrale ou du Sud). Ce sera aussi le cas en 2015 puisque la conférence aura lieu en Allemagne à Heidelberg.

Réalisation de la carte

La carte diffère légèrement de celle réalisée l’année dernière (pour DebConf13) grâce quelques changements de configuration d’xplanet.

Commande utilisée

xplanet -transpng debconf14_planet.png -geometry 1024x512 -projection peters -config debconf14_planet.conf -num_times 1

Deux paramètres ont été modifiés :

  • La carte utilise une projection de Peters plutôt qu’une projection de Mercator. Pour cela, il suffit de remplacer -projection mercator par -projection peters.
  • Avec cette projection, la taille de la Terre n’est pas la même et la zone vide est rempli par défaut par un ciel étoilé. Il est aussi possible de choisir une couleur unie ou sa propre image de fond. Remplacer le paramètre -output par -transpng pour définir le fichier de sortie permet d’avoir un fond transparent.

Fichier debconf14_planet.conf

[earth]
shade=100
marker_file=coords.txt
marker_fontsize=15
map=night.jpg

L’ajout de map permet de définir l’image à utiliser à la place de l’image par défaut. Ici, on obtient une image de la Terre de nuit (qui provient de /usr/share/xplanet/images/night.jpg).

Fichier coords.txt

+44.80 +0.58 "0&1" #Bordeaux, France
+43.65 -79.38 "2" #Toronto, Canada
+59.92 +10.75 "3" #Oslo, Norway
-29.99 -51.22 "4" #Porto Alegre, Brazil
+60.22 +24.66 "5" #Espoo, Finland
+18.91 -98.97 "6" #Oaxtepec, Mexico
+55.96 -3.19 "7" #Edinburgh, Scotland
-37.96 -57.59 "8" #Mar del Plata, Argentina
+39.60 -6.08 "9" #Extremadura, Spain
+40.74 -74.00 "10" #New York City, USA
+44.78 +17.21 "11" #Banja Luka, Republika Srpska, Bosnia and Herzegovina
+12.14 -86.25 "12" #Managua, Nicaragua
+46.87 +6.75 "13" #Le Camp, Vaumarcus, Switzerland
+45.53 -122.67 "14" color=white #Portland, Oregon, USA
+49.24 +8.42 "15" color=yellow #Heidelberg, Germany

Le fichier a simplement été mis à jour (ajout d’Heidelberg, décalage des couleurs).

À bientôt !

Créer un motif pour cowsay

Cowsay est un de ces outils en ligne de commande prouvant que le génie humain est sans limite. Indispensable lors des grandes étapes d’une vie (déclaration d’amour, divorce, post sur IRC, etc.), il est nécessaire de maîtriser cet outil crucial au point de ne faire qu’un avec lui. À la limite 1,2 si vous n’êtes pas ambitieux.

Installation et utilisation

Cowsay est écrit en Perl et est disponible dans toutes les distributions sérieuses :

apt-get install cowsay  #sous Debian et dérivées

Le paquet fournit `cowsay` et `cowthink`. Une démo valant mille mots, voici deux démos pour deux fois plus d’économies :

$ cowsay "Bonjour lecteur"
 _________________
< Bonjour lecteur >
 -----------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ cowthink "Ça c'est fait"
 _______________
( Ça c'est fait )
 ---------------
        o   ^__^
         o  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

Il est possible de changer les yeux, et de faire apparaître la langue avec des paramètres facultatifs. Par exemple :

$ cowsay -t "Malaaaade, je suis malaaade"
 _____________________________
< Malaaaade, je suis malaaade >
 -----------------------------
        \   ^__^
         \  (--)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ cowsay -d "Malaaaade, j'étais trop malaaade"
 __________________________________
< Malaaaade, j'étais trop malaaade >
 ----------------------------------
        \   ^__^
         \  (xx)\_______
            (__)\       )\/\
             U  ||----w |
                ||     ||

Il est aussi possible de changer la vache par un autre dessin. Plus de 50 motifs sont disponibles dans /usr/share/cowsay/cows/. Cependant, nous ne sommes pas limités à ces motifs car nous pouvons fournir notre propre motif :

$ cowsay -f ./rabbit.cow "Je n'ai pas la myxomatose..."
 ______________________________
< Je n'ai pas la myxomatose... >
 ------------------------------
    \    /|
     \  | |   ____
      \ \ |--/ ___\
       \ ) oo (   `
       =(>(\/)<)=_ --._
         (       /     \_
          \    ,(      / )
          | | / _\   ,'-'
         (_(_/ (______)

Voyons comment réaliser un tel prodige !

Créer son propre motif

Le plus simple est de commencer par une version en ascii satisfaisante. Si on veut avoir la possibilité de modifier les yeux, les deux caractères les représentant doivent être l’un à côté de l’autre. Pour le lapin, on commence avec :

$ cat lapin.txt 
         /|
        | |   ____
        \ |--/ ___\
         ) oo (   `
       =(>(\/)<)=_ --._
         (       /     \_
          \    ,(      / )
          | | / _\   ,'-'
         (_(_/ (______)

Pour en faire un fichier utilisable par `cowsay`, le nouveau fichier devra finir par « .cow » et être du code Perl valide.
Ainsi les caractères « \ » et « @ » doivent être protégé par un premier « \ ». L’emplacement (facultatif) de la langue est marqué par $tongue, celui des yeux par $eyes. Les variables $thoughts seront remplacées automatiquement pour relier le motif (ici le lapin) à la bulle contenant le texte.

La variable $the_cow sera définie avec ce motif.

Au final, on obtient :

$the_cow = <<EOC;
    $thoughts    /|
     $thoughts  | |   ____
      $thoughts \\ |--/ ___\\
       $thoughts ) $eyes (   `
       =(>(\\/)<)=_ --._
         (  $tongue   /     \\_
          \\    ,(      / )
          | | / _\\   ,'-'
         (_(_/ (______)
EOC

Évidemment, le résultat est beaucoup moins lisible mais comme c’est du Perl, les traditions sont respectées.

Le résultat en action :

$ cowsay -d -f ./rabbit.cow "Caramba, encore raté"
 ______________________
< Caramba, encore raté >
 ----------------------
    \    /|
     \  | |   ____
      \ \ |--/ ___\
       \ ) xx (   `
       =(>(\/)<)=_ --._
         (  U    /     \_
          \    ,(      / )
          | | / _\   ,'-'
         (_(_/ (______)

Code source et références

Télécharger rabbit.cow

Pour connaître les possibilités non couvertes par l’article, lisez la page de manuel de `cowsay`. C’est la même page qui sert de manuel pour `cowthink`.

La version utilisée pour cet article est la 3.0.3.

La page historique sur `cowsay` par son créateur : https://web.archive.org/web/20120225123719/http://www.nog.net/~tony/warez/cowsay.shtml