Main menu:

Site search

Categories

mars 2025
L M M J V S D
 12
3456789
10111213141516
17181920212223
24252627282930
31  

Archive

Débugger un script shell

Plus un programme ou un script devient complexe et plus il devient important d’avoir des outils pour pouvoir le débugger. On connait gdb, le débuggeur de gcc qui avec des commandes simples permet de débugger un programme. Mais gdb n’est pas utilisable avec vos scripts shell. Malheureusement il n’existe pas nativement de débuggeur pour scripts shell. La seule possibilité que vous ayez est d’utiliser les maigres possibilités de bash pour tracer vos programmes.

La première chose que vous pouvez faire est de tester votre script pour trouver toutes les erreurs de syntaxe que vous avez pu faire en tapant le code. Il est possible de demander à bash de vous les donner sans que le script ne soit exécuté. Il suffit pour cela de lancer le script avec l’option -n de bash. Par exemple vous avez tapé dans votre éditeur de texte favori le script suivant:

#!/bin/bash

for i in *
du
  file "$i"
done

Si vous regardez ce petit script de près, vous vous apercevrez que j’ai tapé du au lieu de do. Si vous lancez le script avec l’option -n, voici ce qui s’affichera dans le terminal:

$ bash -n script.sh
/home/michel/bin/script.sh: script.sh: line 4: Erreur de syntaxe près du symbole inattendu « du »
/home/michel/bin/script.sh: script.sh: line 4: `du'

Par contre si vous faites une erreur dans la commande file et que vous écrivez fole à la place, bash ne vous dira rien car c’est une commande externe à bash et non pas un mot clé du langage de script.
Il n’ y a pas que les fautes de frappe qui sont détectées par cette option; les vraies erreurs de syntaxe aussi évidemment. Par exemple si vous construisez votre boucle for comme en python:

#!/bin/bash

for i in *:
  file "$i"

Voici le résultat affiché dans la console:

$ bash -n script.sh
/home/michel/bin/script.sh: script.sh: line 4: Erreur de syntaxe près du symbole inattendu « file »
/home/michel/bin/script.sh: script.sh: line 4: `  file "$i"'

Pour vous aider dans la mise au point de votre script, vous pouvez aussi utiliser l’option -x qui affiche la commande et ses arguments au moment de l’exécution de celle-ci. Reprenons notre script et lançons le avec l’option -x:

#!/bin/bash

for i in *
do
  file "$i"
done

$ bash -x script.sh
+ for i in '*'
+ file file1.zip
file1.zip: Zip archive data, at least v2.0 to extract
+ for i in '*'
+ file image.PNG
image.PNG: PNG image, 360 x 280, 8-bit/color RGBA, non-interlaced
+ for i in '*'
+ file texte.odt
texte.odt: OpenDocument Text
+ for i in '*'
+ file 'backup'
backup: directory
...

On voit clairement ici que, à chaque étape dans la boucle for, la commande est affichée ainsi que le résultat de celle-ci. Ca permet de tracer le déroulement du programme et voir si, séquentiellement, celui-ci est correct. On peut évidemment ajouter des echo partout où la valeur d’une variable permet de contrôler le flux d’exécution du programme.

Cette option -x peut être introduite directement dans le code source du script et ne doit pas nécessairement être introduit dans la ligne de commande:

#!/bin/bash -x

for i in *
do
  file "$i"
done

est équivalent lors de l’exécution à:

$ bash -x script.sh

De même, cette option peut être mise à on ou à off à l’intérieur même du script dans le cas où vous ne désiriez pas que bash vous affiche toutes les commandes et le résultat de celles-ci mais seulement d’une petite partie de votre script:

#!/bin/bash

set -x    #on

for i in *
do
  file "$i"
done

set +x    #off

set -x met à on l’affichage des commandes et set +x le met à off.

Il y a aussi la solution que vous écriviez vous-même une fonction plus ou moins intelligente pour vous aidez dans la recherche des erreurs dans vos scripts.

Impossible d’éjecter le CD ou DVD

Il y a plusieurs méthode pour éjecter un CD ou un DVD du lecteur. La première est évidemment de pousser sur le bouton d’éjection en face avant du lecteur. La seconde est de cliquer avec le bouton droit de la souris sur l’icône du CD ou DVD monté qui apparaît sur le bureau et de choisir Ejecter dans le menu.
Vous pouvez même utiliser la ligne de commande pour le faire:

$ eject /dev/scd0

Remplacez /dev/scd0 par le périphérique qui chez vous correspond au lecteur CD.
Pour refermer le tiroir du lecteur, tapez:

$ eject -t /dev/scd0

Mais parfois, le CD ou le DVD ne veut pas s’éjecter. Vous avez beau pousser sur le bouton ou lancer la commande ci-dessus, il n’y a rien à faire. Ubuntu vous signale juste qu’un processus utilise le lecteur et qu’il est impossible d’éjecter le disque.
Il suffit, dans ce cas, de trouver quel est le processus en cause et de le tuer. Pas simple de prime abord; la commande ps ne renvoie pas ce genre de renseignement. Heureusement pour nous, il y a une autre commande fuser qui peut nous le dire. Par exemple, si je suis en train de regarder un DVD avec vlc, fuser me renverra:

$ fuser /dev/scd0
/dev/scd0:           20865

Le numéro du processus sera plus que probablement différent chez vous. Maintenant, si je veux savoir à quel programme correspond ce processus, je fais:

$ ps -ef | grep 20865
michel   20865     1 20 10:58 ?        00:00:08 vlc /media/cdrom0

On voit que j’ai lancé vlc pour lire le DVD.
Pour tuer ce processus, je pourrais faire un kill de ce processus en tapant simplement:

$ kill 20865

Mais fuser permet de faire tout cela en une seule commande:

$ fuser -k /dev/scd0
/dev/scd0:           20865

Cette commande retourne donc le processus qui bloquait votre lecteur et, en plus, le tue de façon à libérer le lecteur.

Une remarque intéressante à faire au sujet de cette commande fuser, est que comme Linux considère que tout est fichier, qu’un périphérique est un fichier, fuser permet aussi de débloquer un fichier qui serait bloquer par un processus.
Il vous est sûrement déjà arrivé de vouloir supprimer un fichier quelconque et de ne pas pouvoir le faire, Ubuntu vous disant que le fichier est utilisé par une autre application. Et bien fuser vous sortira aussi de ce mauvais pas en vous disant quel processus à ouvert le fichier en question et ne veut plus le lâcher:

$ fuser mon_fichier

Vous pouvez évidemment aussi utiliser l’option -k pour tuer le processus bloquant:

$ fuser -k mon_fichier

Pour plus de détail sur fuser, je vous renvoie bien sûr vers la page de manuel.

Déplacer les fichiers mysql et apache

Lorsqu’on installe Apache2 et mysql, les fichiers source html (ou php) et les fichiers base de données sont respectivement stockés dans /var/www et /var/lib/mysql. Ce n’est pas, nous en conviendrons, le meilleur endroit. Il vaut mieux que ces fichiers soient stockés à un endroit où un utilisateur du système aurait accès facilement à ceux-ci. Il est aussi recommandé de les mettre sur une partition autre que celle où est installé le système de façon à ce qu’une réinstallation ou une mise à jour puisse se faire sans risque pour ces fichiers. On pourrait imaginer créer une partition séparée pour /var mais /var n’est pas un répertoire auquel les utilisateurs ont accès facilement.
Ce que je fais, moi, c’est créer un utilisateur spécial et je place les fichiers html et les fichiers base de données directement dans le home de cet utilisateur. Si on veille à ce que cet utilisateur fasse partie du groupe mysql et www-data, il aura accès très facilement aux fichiers.

Déplacement des fichiers apache

Nous allons d’abord arrêter le service apache2 le temps de faire les modifications:

$ sudo /etc/init.d/apache2 stop

Maintenant que le service est arrêté, on modifie le fichier de configuration de façon à lui donner le nouveau répertoire où apache doit aller chercher les fichiers à afficher. Le fichier de configuration se trouve dans /etc/apache2/sites-available/. Par défaut, il s’appelle default. Si vous avez un nom de domaine, le fichier sera du style mondomaine.tld. Dans ce fichier, il faut remplacer les /var/www par /home/user/www. Pour éditer le fichier, tapez:

$ sudo nano /etc/apache2/sites-available/default

On copie maintenant les fichiers qui se trouvaient dans /var/www pour les transférer dans /home/user/www:

$ sudo cp -a /var/www /home/user/www/

Et on relance apache2:

$ sudo /etc/init.d/apache2 restart

Déplacement des fichiers mysql

Comme pour apache, on commence par arrêter le service:

$ sudo /etc/init.d/mysql stop

On modifie le fichier de configuration de mysql qui est /etc/mysql/my.cnf et on modifie la ligne qui contient datadir=/var/lib/mysql par datadir=/home/user/mysql:

$ sudo nano /etc/mysql/my.cnf

Ensuite, on copie les fichiers contenant les tables et qui se trouvaient dans /var/lib/mysql dans le nouveau répertoire:

$ sudo cp -a /var/lib/mysql /home/user/mysql

Il faut aussi modifier apparmor qui est un programme permettant de créer des profils de sécurité pour chaque programme. Ubuntu utilise apparmor depuis pas mal de temps et notamment avec mysql. Nous devons donc modifier le fichier /etc/apparmor.d/usr.sbin.mysqld qui contient le profil de mysql et y remplacer /var/lib/mysql par /home/user/mysql:

$ sudo nano /etc/apparmor.d/usr.sbin.mysqld

Il ne reste plus qu’à recharger apparmor pour lui faire prendre en compte les modifications et à relancer mysql:

$ sudo /etc/init.d/apparmor reload
$ sudo /etc/init.d/mysql restart

Vous aurez remarqué que j’utilise nano pour éditer les fichiers de configuration. Je suis parti du principe que mysql et apache2 sont installés sur un serveur ne possédant pas d’interface graphique et donc pas de possibilité d’utiliser gedit et je pense que nano est quand même plus simple d’utilisation que vi par exemple.

Parasite

Parasite est un outil qui peut être très utile à toute personne qui développe de petites ou de grosses applications en utilisant GTK pour la partie interface graphique. Ce module qui s’intercale dans votre application de façon très simple, vous permet de débugger votre interface graphique (GUI en anglais ou IHM en français) en vous donnant la hiérarchie des widgets utilisés ainsi que leurs propriétés. Parasite vous permet aussi d’agir sur ces propriétés et de les modifier et ainsi de voir immédiatement l’effet de vos modifications sur votre interface graphique.
Ceux d’entre-vous qui utilisent firebug sous Firefox ne seront pas dépaysés. L’interface y ressemble avec son bouton ‘Inspect’ qui permet de voyager dans les widgets de l’interface graphique.
Voici un screenshot vous montrant à quoi ressemble Parasite. Dans l’exemple, Parasite est utilisé pour inspecter l’interface graphique de la calculatrice Gnome (gcalctool). Je me suis amusé à y changer certains labels de boutons et à en rendre un invisible. Mais ce n’est évidemment pas tout ce que peu faire Parasite; ça ne se limite bien sûr pas à changer le label des boutons!


Capture-Parasite

Pour installer Parasite, downloadez le fichier .tar.gz à cette adresse et décompressez l’archive:
http://github.com/chipx86/gtkparasite/tarball/master

Il va falloir compiler le programme mais rassurez-vous, cela se passe sans problème.
En regardant dans le répertoire où l’archive est décompressée, on remarque qu’il n’y a pas de fichier configure. Heureusement, le script autogen.sh va nous le créer. ensuite, la compilation se fait « as usual » en utilisant configure/make/make install:

$ ./autogen.sh
$ ./configure
$ make
$ sudo make install

Vérifiez que toutes ces étapes se soient bien passées et qu’aucun message d’erreur ne soit affiché dans le terminal.
il reste ensuite à créer un lien symbolique dans /usr/lib pointant vers /usr/local/lib/gtk-2.0/modules/libgtkparasite.so.

$ cd /usr/lib
$ sudo ln -s /usr/local/lib/gtk-2.0/modules/libgtkparasite.so libgtkparasite.so

Pour attacher Parasite à une application, il suffit d’intercaler Parasite de cette manière:

$ GTK_MODULES=gtkparasite gcalctool

Vous devez bien évidemment, dans la ligne ci-dessus, remplacer gcalctoolgcalctool par le nom de l’application dont vous voulez débugger l’interface graphique.

SweetHome3D

Je cherchais un programme spécialisé pour pouvoir dessiner les plans des pièces de mon habitation et le choix a été vite fait puisque SweetHome3D est le seul programme de ce type sous Linux. Alors attention, ce n’est pas un programme de dessin industriel genre Autocad. C’est un simple programme d’aménagement intérieur et de décoration comme il se définit lui-même mais ce qu’il fait, il le fait pas mal.
Il vous permet de dessiner rapidement le plan d’une pièce, d’une habitation, d’y placer le mobilier que vous désirez, à la taille voulue et d’en avoir un aperçu sous forme d’une vue 3D. Vous pouvez en outre rajouter des librairies d’objets (meubles, déco,…) ou les dessiner vous même.

Ce programme est distribué sous license GNU GPL et est écrit en java ce qui lui donne ce petit air caractéristique des applications utilisant les widgets java.

Voici à quoi il ressemble:


SweetHome3D

Pour l’installer, vous avez le choix entre utiliser Java Web Start ou télécharger un paquet complet incluant java. Dans mon cas, malgré le fait que java soit installé sur mon PC, je n’ai jamais réussi à faire fonctionner la version Java Web Start. Je me suis donc rabattu sur le paquet complet téléchargeable ici. Ce paquet fait tout de même plus de 45MB. Une fois téléchargé, la seule chose à faire est de le décompresser dans le répertoire de votre choix. Comme d’habitude, je vous propose de le faire dans le répertoire /opt qui est destiné à ce genre d’application. Ouvrez un terminal, placez-vous dans le répertoire où vous avez sauvegardé l’archive téléchargée et décompressez le fichier de cette façon:

$ sudo tar -C /opt -zxvf SweetHome3D-2.0-linux-x86.tgz

Pour le lancer, il suffit de taper dans un terminal la commande suivante:

$ /opt/SweetHome3D-2.0/SweetHome3D

Je vous invite à créer un lanceur dédicacé à ce programme ou mieux, à créer une entrée dans le menu Graphisme correspondant à SweetHome3D. Pour cela, rendez-vous dans le menu Sytème/Préférences/Menu principal.

Colorisation syntaxique avec pygments

Elle consiste à donner à chaque élément d’un texte un style particulier. En programmation, cela consiste à donner une couleur et un style (gras, italique…) à chaque élément constituant le code source. La colorisation syntaxique rend le code plus lisible donc plus facilement compréhensible.

La plupart des éditeurs de texte le font automatiquement mais si vous devez formater le texte vous même pour l’afficher dans un wiki, une page web ou un blog, c’est une autre paire de manche.
J’utilise par exemple deux scripts qui me permettent de faire la colorisation syntaxique de code C++ ou python et me donnent un fichier html que je peux inclure dans une page web. Le problème est que si je veux documenter du code PHP, javascript ou des requètes SQL et faire la colorisation syntaxique moi-même, il faudra que je réécrive un nouveau script pour chaque langage. Heureusement pour moi, j’ai découvert une application écrite en python et trouvable sur http://pygments.org.

Pygments permet la colorisation syntaxique d’un très grand nombre de langages dont par exemple bash, C,C++, C#, Lisp, Lua, Delphi, PHP, Perl Python, Ruby, Tcl, Java, Javascript … Et je n’ai mis ici que les langages les plus connus. Il ye en a plein d’autres. Pygments permet aussi la colorisation syntaxique de fichiers de configuration, ini, css, html, sql, xml, latex,… De surcroît, on peut choisir le format de sortie: html, latex, rtf…

Pygments peut être utilisé en ligne de commande ou en tant que librairie dans un projet.

Pour l’installer, downloadez le fichier Pygments-1.1.tar.gz depuis http://pypi.python.org/pypi/Pygments
Ensuite tapez les commandes suivantes dans un terminal pour extraire de l’archive les fichiers et exécuter le fichier d’installation.

$ tar -zxvf Pygments-1.1.tar.gz
$ cd Pygments-1.1
$ sudo python setup.py install

Exemple d’utilisation en ligne de commande pour générer du code html:

Disons que nous voulons coloriser le bout de code python suivant:

# Returns the factorial of a number
def factorial(x):
    if x < 0:
        raise ValueError("Factorial is only defined for x >= 0")
    y = 1
    while x >= 2:
        y *= x
        x -= 1
    return y

Ce bout de code, plaçons-le dans un fichier appelé test.py et tapons la ligne suivante dans notre terminal:

$ pygmentize -f html -l python -o test.html test.py

-l choix du lexer, c’est à dire le module chargé de parser le code donné dans le langage spécifié et le séparer en ses composants (keywords, comments, chaînes de caractères…)

-f choix du formateur, c’est à dire le format sous lequel vous désirez le fichier de sortie (html, latex, rtf…).

Le résultat obtenu est le fichier html test.html ci-dessous:

<div class="highlight"><pre><span class="c"># Returns the factorial of a number</span>
<span class="k">def</span> <span class="nf">factorial</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">x</span> <span class="o"><</span> <span class="mf">0</span><span class="p">:</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"Factorial is only defined for x >= 0"</span><span class="p">)</span>
    <span class="n">y</span> <span class="o">=</span> <span class="mf">1</span>
    <span class="k">while</span> <span class="n">x</span> <span class="o">>=</span> <span class="mf">2</span><span class="p">:</span>
        <span class="n">y</span> <span class="o">*=</span> <span class="n">x</span>
        <span class="n">x</span> <span class="o">-=</span> <span class="mf">1</span>
    <span class="k">return</span> <span class="n">y</span>
</pre></div>

Vous remarquerez que chaque constituant du code a son propre style avec sa classe propre. A vous de déterminer ce style en donnant au navigateur une feuille de style (css) compatible. Vous pouvez vous aider en utilisant la commande suivante qui liste les différents styles utilisés sous forme de css:

$ pygmentize -f html -S colorful 

.hll { background-color: #ffffcc }
.c { color: #808080 } /* Comment */
.err { color: #F00000; background-color: #F0A0A0 } /* Error */
.k { color: #008000; font-weight: bold } /* Keyword */
.o { color: #303030 } /* Operator */
.cm { color: #808080 } /* Comment.Multiline */
.cp { color: #507090 } /* Comment.Preproc */
.c1 { color: #808080 } /* Comment.Single */
.cs { color: #cc0000; font-weight: bold } /* Comment.Special */
.gd { color: #A00000 } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.gr { color: #FF0000 } /* Generic.Error */
.gh { color: #000080; font-weight: bold } /* Generic.Heading */
.gi { color: #00A000 } /* Generic.Inserted */
.go { color: #808080 } /* Generic.Output */
.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.gt { color: #0040D0 } /* Generic.Traceback */
.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.kp { color: #003080; font-weight: bold } /* Keyword.Pseudo */
.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.kt { color: #303090; font-weight: bold } /* Keyword.Type */
.m { color: #6000E0; font-weight: bold } /* Literal.Number */
.s { background-color: #fff0f0 } /* Literal.String */
.na { color: #0000C0 } /* Name.Attribute */
.nb { color: #007020 } /* Name.Builtin */
.nc { color: #B00060; font-weight: bold } /* Name.Class */
.no { color: #003060; font-weight: bold } /* Name.Constant */
.nd { color: #505050; font-weight: bold } /* Name.Decorator */
.ni { color: #800000; font-weight: bold } /* Name.Entity */
.ne { color: #F00000; font-weight: bold } /* Name.Exception */
.nf { color: #0060B0; font-weight: bold } /* Name.Function */
.nl { color: #907000; font-weight: bold } /* Name.Label */
.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.nt { color: #007000 } /* Name.Tag */
.nv { color: #906030 } /* Name.Variable */
.ow { color: #000000; font-weight: bold } /* Operator.Word */
.w { color: #bbbbbb } /* Text.Whitespace */
.mf { color: #6000E0; font-weight: bold } /* Literal.Number.Float */
.mh { color: #005080; font-weight: bold } /* Literal.Number.Hex */
.mi { color: #0000D0; font-weight: bold } /* Literal.Number.Integer */
.mo { color: #4000E0; font-weight: bold } /* Literal.Number.Oct */
.sb { background-color: #fff0f0 } /* Literal.String.Backtick */
.sc { color: #0040D0 } /* Literal.String.Char */
.sd { color: #D04020 } /* Literal.String.Doc */
.s2 { background-color: #fff0f0 } $ pygmentize -O full -o test.html test.py/* Literal.String.Double */
.se { color: #606060; font-weight: bold; background-color: #fff0f0 } /* Literal.String.Escape */
.sh { background-color: #fff0f0 } /* Literal.String.Heredoc */
.si { background-color: #e0e0e0 } /* Literal.String.Interpol */
.sx { color: #D02000; background-color: #fff0f0 } /* Literal.String.Other */
.sr { color: #000000; background-color: #fff0ff } /* Literal.String.Regex */
.s1 { background-color: #fff0f0 } /* Literal.String.Single */
.ss { color: #A06000 } /* Literal.String.Symbol */
.bp { color: #007020 } /* Name.Builtin.Pseudo */
.vc { color: #306090 } /* Name.Variable.Class */
.vg { color: #d07000; font-weight: bold } /* Name.Variable.Global */
.vi { color: #3030B0 } /* Name.Variable.Instance */
.il { color: #0000D0; font-weight: bold } /* Literal.Number.Integer.Long */

Il vous est aussi possible d’ajouter des numéros de lignes. Ceci crée en fait un tableau html dont la première colonne est le numéro de la ligne:

$ pygmentize -f html -l python -O style=colorful,linenos=1 -o test.html test.py

Si vous préférez un fichier html complet représentant une page complète avec entête et style utilisable directement avec le navigateur:

$ pygmentize -O full -o test.html test.py

Le résultat est ci-dessous. Notez l’entête, les CSS inclus dans le fichier et finalement votre code source formaté:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>
  <title></title>
  <meta http-equiv="content-type" content="text/html; charset=latin1">
  <style type="text/css">
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
pre { line-height: 125%; }
body .hll { background-color: #ffffcc }
body  { background: #f8f8f8; }
body .c { color: #408080; font-style: italic } /* Comment */
body .err { border: 1px solid #FF0000 } /* Error */
body .k { color: #008000; font-weight: bold } /* Keyword */
body .o { color: #666666 } /* Operator */
body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
body .cp { color: #BC7A00 } /* Comment.Preproc */
body .c1 { color: #408080; font-style: italic } /* Comment.Single */
body .cs { color: #408080; font-style: italic } /* Comment.Special */
body .gd { color: #A00000 } /* Generic.Deleted */
body .ge { font-style: italic } /* Generic.Emph */
body .gr { color: #FF0000 } /* Generic.Error */
body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
body .gi { color: #00A000 } /* Generic.Inserted */
body .go { color: #808080 } /* Generic.Output */
body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
body .gs { font-weight: bold } /* Generic.Strong */
body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
body .gt { color: #0040D0 } /* Generic.Traceback */
body .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
body .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
body .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
body .kp { color: #008000 } /* Keyword.Pseudo */
body .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
body .kt { color: #B00040 } /* Keyword.Type */
body .m { color: #666666 } /* Literal.Number */
body .s { color: #BA2121 } /* Literal.String */
body .na { color: #7D9029 } /* Name.Attribute */
body .nb { color: #008000 } /* Name.Builtin */
body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
body .no { color: #880000 } /* Name.Constant */
body .nd { color: #AA22FF } /* Name.Decorator */
body .ni { color: #999999; font-weight: bold } /* Name.Entity */
body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
body .nf { color: #0000FF } /* Name.Function */
body .nl { color: #A0A000 } /* Name.Label */
body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
body .nt { color: #008000; font-weight: bold } /* Name.Tag */
body .nv { color: #19177C } /* Name.Variable */
body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
body .w { color: #bbbbbb } /* Text.Whitespace */
body .mf { color: #666666 } /* Literal.Number.Float */
body .mh { color: #666666 } /* Literal.Number.Hex */
body .mi { color: #666666 } /* Literal.Number.Integer */
body .mo { color: #666666 } /* Literal.Number.Oct */
body .sb { color: #BA2121 } /* Literal.String.Backtick */
body .sc { color: #BA2121 } /* Literal.String.Char */
body .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
body .s2 { color: #BA2121 } /* Literal.String.Double */
body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
body .sh { color: #BA2121 } /* Literal.String.Heredoc */
body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
body .sx { Colorisation syntaxique avec pygmentscolor: #008000 } /* Literal.String.Other */
body .sr { color: #BB6688 } /* Literal.String.Regex */
body .s1 { color: #BA2121 } /* Literal.String.Single */
body .ss { color: #19177C } /* Literal.String.Symbol */
body .bp { color: #008000 } /* Name.Builtin.Pseudo */
body .vc { color: #19177C } /* Name.Variable.Class */
body .vg { color: #19177C } /* Name.Variable.Global */
body .vi { color: #19177C } /* Name.Variable.Instance */
body .il { color: #666666 } /* Literal.Number.Integer.Long */

  </style>
</head>
<body>
<h2></h2>

<div class="highlight"><pre><span class="c"># Returns the factorial of a number</span>
<span class="k">def</span> <span class="nf">factorial</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">x</span> <span class="o"><</span> <span class="mf">0</span><span class="p">:</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"Factorial is only defined for x >= 0"</span><span class="p">)</span>
    <span class="n">y</span> <span class="o">=</span> <span class="mf">1</span>
    <span class="k">while</span> <span class="n">x</span> <span class="o">>=</span> <span class="mf">2</span><span class="p">:</span>
        <span class="n">y</span> <span class="o">*=</span> <span class="n">x</span>
        <span class="n">x</span> <span class="o">-=</span> <span class="mf">1</span>
    <span class="k">return</span> <span class="n">y</span>
</pre></div>
</body>
</html>

Et vous pouvez voir ici le résultat de tous vos efforts.