Iterator et iterable en javascript

Les concepts de d’itérator et d’itérable font leur entrée avec l’arrivée de ES6.

Iterator

Un iterator est un objet possédant une méthode next() et renvoyant quand elle est appelée une structure contenant les propriétés done et value

Exemple d’iterator

function myArrayIterator(arr) {
  var index = 0;
  return {
    next : function {
      if (index < arr.length) {
        return { done: false, value: arr[index++] };
      } else {
        return { done: true };
      }
    }
  }
}
var it = myArrayIterator(['s1', 's2']);
console.log(it.next()); // { done: false, value: "s1" }
console.log(it.next()); // { done: false, value: "s2" }
console.log(it.next()); // { done: true }

Cet iterator n’est pas iterable, c’est à dire qu’il ne peut pas être parcouru par une boucle for ..of

var it2 = myArrayIterator(['s1', 's2'])
for(var item of it2) { // TypeError: it2[Symbol.iterator] is not a function
  console.log(item);
}

Iterable

Afin d’être itérable, un objet doit implémenter la méthode @@iterator, cela signifie que l’objet (ou un des objets de sa chaîne de prototypes) doit avoir une propriété avec une clé Symbol.iterator. Cette méthode doit renvoyer un object iterator.

Rendons notre objet myArrayIterator iterable :

function myArrayIteratorIterable(arr) {
  var index = 0;
  return {
    [Symbol.iterator] : function () {
      return  {
        next : function () {
          if (index < arr.length) {
            return { done: false, value: arr[index++] };
          } else {
            return { done: true };
          }
        }
      }
    }
  }
}

var it2 = myArrayIteratorIterable(tab)
for(var item of it2) {
  console.log(item);
}
// s1
// s2

Exemple d’objet iterable

var batman = new (function() {
  var self = this;
  var index=0;
  
  
  this.nom = 'Wayne';  
  this.prenom = 'Bruce';
  this.parler = function() {
    console.log('Bonjour');
  }
  
  this[Symbol.iterator] = function () {
    var keys = Object.keys(self);
    return { 
      next : function() {
        if (index < keys.length) {
          return { done: false, value: self[keys[index++]] };
        } else {
          return { done: true };
        }
      }
    }
  };

})();

for(var item of obj) {
  console.log(i);
}

// "Wayne"
// "Bruce"
// function obj</this.parler()

 

 

 

 

 

L’asynchronisme en JavaScript

Quiconque a déjà programmé en JavaScript, s’est déjà confronté aux notions de programmation asynchrone. Voyons 3 façons d’appréhender la problématique.

Que signifie « Asynchrone »

Plutôt que d’avoir une valeur retournée directement par votre fonction, vous passez une callback qui sera appelée lorsque le résultat sera disponible. Par exemple, lors d’un appel AJAX, durant le traitement du serveur, le thread JavaScript n’est pas bloqué en attendant le retour. Il traite d’autres instructions. Si ce n’était pas le cas, la page web serait paralysée pendant toute la durée du traitement serveur. L’idée est donc de ne pas bloquer le thread principal dans l’attente de la réponse et de fournir une fonction qui sera appelée lorsque le résultat sera disponible. Un message est mis dans la queue pour être traité une fois la réponse reçue. Ainsi, le navigateur peut continuer ses traitements pendant que l’appel HTTP est toujours en cours.

De par sa nature monithread, en JavaScript les I/O sont non bloquantes. Cela signifie qu’il n’y a pas d’attente de la réponse. Le code continue de s’exécuter. Le traitement de retour est positionné dans une callback qui sera exécutée quand la réponse surviendra.

Déroulement d’un appel AJAX:
1 – lancement de la requête AJAX
2 – Enregistrement d’une callback de retour dans la queue
3 – Traitement d’autres messages de la queue
4 – Exécution de la callback quand la réponse est arrivée. La stack doit bien évidement être vide pour traiter la réponse.

Exemple :

makeAjaxRequest("http://www.google.fr", function(response) {
    console.log("Retour appel ajax");
});
console.log("Fin");

Sortie de la console :

Fin
Retour appel ajax

On voit bien que la première instruction console.log n’est pas la première exécutée.

 

Patterns asynchrones

Callback

En JavaScript, les fonctions sont d’ordre supérieur c’est à dire qu’elles peuvent prendre une ou plusieurs fonctions comme entrée et renvoyer une fonction comme retour. De la première caractéristique découle qu’il est possible de passer une fonction en argument d’une autre et de l’exécuter plus tard dans le code. C’est le principe même des callbacks.
Une fonction de callback est une fonction passée en paramètre d’une autre fonction et appelée à l’intérieur de cette dernière.

Le callback hell est la complexité qui apparait lorsque l’on essaie de séquencer du code asynchrone utilisant des callbacks. Il en résulte du code imbriqué, difficile à lire et à maintenir. Le code ne se lit pas verticalement, la dernière ligne n’est pas la dernière instruction mais la plus profonde.

Exemple de callback hell aka pyramid of doom.

function1(args, function () {
    function2(args, function () {
        function3(args, function () {
            function4(args, function () {
                console.log('Done!');
            });
        });
    });
});

Le code est péniblement refactorable. Imaginez que vous souhaitiez inverser les fonctions 2 et 3 – et pour un peu plus de réalisme elles n’ont pas un nom similaire ni les mêmes arguments. Il vous faut coupez/coller la fonction 3 au dessus de la 2, réimbriquer le code et le réindenter. C’est assez laborieux.
Il est possible de nommer et d’extraire les fonctions, mais cela ne résout pas le problème

En nommant les fonctions de callback nous arrivons à quelques chose de mieux. La profondeur du code est moindre, mais il est tout de même difficile d’avoir une vue globale de l’enchainement des fonctions. Il faut naviguer de fonction en fonction pour découvrir le séquencement des appels.

function1(args, callback1);

function callback1() {
    function2(args, callback2);
}

function callback2() {
    function3(args, callback3);
}

function callback3() {
    function4(args, callback4);
});

function callback4 () {
    console.log('Done!');
});

 

Promesse

Le but des promesses est de simplifier l’écriture de code asynchrone. Les API utilisant les promesses ne prennent pas de callback en paramètre mais renvoient un objet promesse. Un objet promesse n’a que quelques méthodes, dont la plus importante est then. La méthode then prend un ou deux arguments, le premier est appelé quand la promesse est résolue (succès) et le second lorsqu’elle est rejetée (erreur). Il est possible de chainer les promesses grâce à la méthode then. Pour cela, la fonction de traitement peut renvoyer une promesse ou une valeur brute qui sera passé en paramètre de la prochaine fonction.
Je ne rentre volontairement pas plus dans le détail car il existe de nombreux articles expliquant le fonctionnement des promesses.

Récrivons l’exemple précédent avec des promesses.

function1(args)
  .then(callback1)
  .then(callback2, callbackError2)
  .then(callback3)
  .then(callback4);

function callback1() {
    return function2(args);
}

function callback2() {
	return function3(args);
}
function callbackError2() {
	console.log("Error2");
}

function callback3() {
	return function4(args);
});

function callback4 () {
	console.log('Done!');
});

Le séquencement est immédiatement perceptible en regardant les « then ». La gestion des erreurs est également simplifiée. Si une promesse est rejetée, l’erreur se propage dans tout les then gérant une erreur.

Generator

Pour une présentation détaillé des générator, je vous invite à lire la présentation très complète de .

En synthèse, les générators arrivent dans ES6 et ne sont donc pas encore supportés par tous les navigateurs. Un générator est une fonction préfixée par le symbole « * ». La fonction est alors en attente jusqu’à ce qu’un appel à la méthode « next » soit effectué. Chaque appel à « next » exécute la fonction jusqu’au prochain « yield »

Exemple :

function simpleGenerator(){
  yield "first";
  yield "second";
  yield "third";
  for (var i = 0; i < 3; i++) {
    yield i;
  }
}

var g = simpleGenerator();
console.log(g.next()); // { value: "first", done: false }
console.log(g.next()); // { value: "second", done: false }
console.log(g.next()); // { value: "third", done: false }
console.log(g.next()); // { value: 0, done: false }
console.log(g.next()); // { value: 1, done: false }
console.log(g.next()); // { value: 2, done: false }
console.log(g.next()); // { value: undefined, done: true }

Il est possible d’utiliser les générators pour créer des iterators ou faire de l’asynchronisme.
L’exemple qui suit est une illustration de ce qu’il est possible de faire. L’article de expose un exemple plus complet et plus robuste.

Exemple simple:

function request(url) {
    // this is where we're hiding the asynchronicity,
    // away from the main code of our generator
    // `it.next(..)` is the generator's iterator-resume
    // call
    makeAjaxCall( url, function(response){ //callback de succès
        it.next( response );
    },
	function(err) { // callback d'erreur
		it.throw(err);
	}
	);
    // Note: nothing returned here!
}

function *main() {
    var result1 = yield request( "http://some.url.1" );
    console.log("Retour appel 1 =>"+result1);

	// Gestion des erreurs pour cet appel AJAX
	try {
		var result2 = yield request( "http://some.url.2?id=" + result1.id );
		console.log( "The value you asked for: " + result2.value );
	}
	catch(e) {
		console.log("Erreur " +e);
	}
}

var it = main();
it.next(); // get it all started

La fonction main est un generator.

  1. it.next() exécute le generator jusqu’au premier yield
    La méthode request est exécutée, l’appel AJAX est donc lancé.
  2. Le generator est en pause.
  3. Le retour de l’appel AJAX déclenche la callback.
    La callback lance la commande it.next() en passant en paramètre les données de retour
  4. Le generator continue jusqu’au prochain yield
    La méthode request est exécutée, l’appel AJAX est donc lancé.
  5. Le generator est en pause.
  6. Le retour de l’appel AJAX déclenche la callback.
    La callback lance la commande it.next() en passant en paramètre les données de retour
  7. Fin

Hormis la présente de yield dans le code, la structure est identique à du code synchrone. Y compris la gestion des exceptions.

Sources

https://msdn.microsoft.com/fr-fr/library/windows/apps/hh700330.aspx
http://www.infoq.com/fr/news/2014/05/promises-javascript
http://www.infoq.com/fr/news/2014/05/promises-javascript
http://javascriptissexy.com/understand-javascript-callback-functions-and-use-them/
http://seajones.co.uk/do-we-need-to-beat-callback-hell/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators

JavaScript concepts clés : monothread et eventloop

Avant de présenter les différents patterns pour gérer l’asynchronisme en JavaScript, il est préférable de connaitre quelques concepts clés comme l’exécution sur un seul thread ou encore l’event loop. Cet article à pour but des les présenter.

Un seul thread pour l’application

JavaScript est un langage monothread, c’est à dire qu’à un instant T, un seul morceau de code s’exécute. On peut considérer, qu’une fonction est un morceau de code indivisible : quand un moteur JavaScript débute l’exécution d’une fonction il finit son exécution jusqu’à la fin (principe de « run to completion »).
Ce modèle possède un désavantage : l’appel d’un processus de longue durée bloque toute exécution tant que ce processus n’est pas terminé. Les éléments d’interface utilisateur cessent de répondre, les animations sont suspendues et aucun autre code de l’application ne peut s’exécuter. Généralement, le navigateur affiche un message de la sorte « Le script met trop de temps à répondre ».

Event loop

Il faut savoir que JavaScript gère la concurrence grâce à une « boucle d’évènements ». Ce modèle est différent de la gestion faite par des langages comme C ou Java. Afin de la comprendre ce qu’est l’event loop, trois parties importantes d’un moteur JavaScript méritent d’être présentées. Bien que l’implémentation des différents moteurs soient différentes, le principe reste vrai pour chacun d’eux.

eventloop1

Heap : La Heap est la partie la plus simple. C’est une zone de mémoire où vivent les objets (variables, fonctions …).

Stack : La stack est l’endroit où les fonctions en cours d’exécutions sont placées. Si une fonction A() lance une fonctin B() il y a deux niveaux dans la stack.
A chaque fois qu’une fonction est ajoutée à la stack elle est appelée « frame ». Les « frames » contiennent des pointeurs vers les fonctions situées dans la heap, vers les objects accessibles dans le scope de la fonction et bien sûr les paramètres d’appel de la fonction.

Queue : file de messages à traiter. Chaque message est associé à une fonction. Lorsque la pile est vide, c’est au tour du prochain message d’être traité. Ce message rempli alors la stack. Le traitement d’un message est fini quand la stack devient vide.
Si vous codez setTimeout(function() { console.log(‘pouet’); }, 10);, cette fonction anonyme sera mise dans la queue.
Aucune fonction dans la queue ne sera exécutée tant que la stack n’est pas vide. C’est pour cela que le deuxième paramètre de la fonction setTimeout assure un temps minimum avant l’exécution
et non pas un temps garanti.

Donnons vie à ce schéma.

 

Sources

https://thomashunter.name/blog/the-javascript-event-loop-presentation/
https://developer.mozilla.org/fr/docs/Web/JavaScript/Guide/Boucle%C3%89v%C3%A9nements

 

 

Installer docker sous debian wheezy

Cet article à pour but de décrire comment installer docker sous debian wheezy. Cela n’est pas aussi facile que prévu (j’ai eu des petits soucis avec cgroup)

1 – Installer un kernel > 3.8
Tout d’abord le noyau de debian wheezy n’est pas assez récent pour supporter docker. Heureusement, les backports sont là pour remédier à cela.
Ajouter la ligne suivante dans le fichier /etc/apt/sources.list puis lancer un aptitude update

deb http://http.debian.net/debian wheezy-backports main contrib non-free

Installer le noyau venant des backports :

aptitude install -t wheezy-backports linux-image-amd64

2 – Installer docker
L’installation s’effectue à partir du binaire docker

wget https://get.docker.com/builds/Linux/x86_64/docker-latest -O docker
chmod +x docker

Installer cgroup :

aptitude install cgroup-bin

3 – Lancer docker au boot
Créer le fichier /etc/init.d/docker avec le contenu ci-dessous :

#!/bin/bash
 # /etc/init.d/docker
 #
 ### BEGIN INIT INFO
 # Provides: docker
 # Required-Start: $local_fs $remote_fs $network vboxdrv
 # Should-Start:
 # Should-Stop:
 # Required-Stop:
 # Default-Start: 2 3 4 5
 # Default-Stop: 0 1 6
 # X-Interactive: true
 # Short-Description: Start docker
 # Description: Start docker
 ### END INIT INFO

 #
 # main part
 #
 #PATH=/sbin:/usr/sbin:/usr/bin:/bin
 LOG=/var/log/mydocker.log
DOCKER_CMD_RUN="PATH_TO_DOCKER_BINARY -d &"

cgroupfs_mount() {
 # see also https://github.com/tianon/cgroupfs-mount/blob/master/cgroupfs-mount
 if grep -v '^#' /etc/fstab | grep -q cgroup \
 || [ ! -e /proc/cgroups ] \
 || [ ! -d /sys/fs/cgroup ]; then
 return
 fi
 if ! mountpoint -q /sys/fs/cgroup; then
 mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup
 fi
 (
 cd /sys/fs/cgroup
 for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do
 mkdir -p $sys
 if ! mountpoint -q $sys; then
 if ! mount -n -t cgroup -o $sys cgroup $sys; then
 rmdir $sys || true
 fi
 fi
 done
 )
 }

case "$1" in
 start)
 echo `date` echo "Starting docker" >> $LOG
 cgroupfs_mount
 eval $DOCKER_CMD_RUN
 ;;
 stop)
 echo `date` "Stopping docker" >> $LOG
 killall docker
 ;;
 esac

Le script fourni permet de lancer docker avec SysV init. Il faut l’ajouter au boot via la commande

update-rc.d docker defaults

La fonction cgroupfs_mount permet de monter les filesystems cgroup afin d’éviter l’erreur suivante : docker failed to find the cgroup root

Voir stackoverflow si besoin : https://github.com/docker/docker/issues/8791

Changer le répertoire de mysql sous debian wheezy

Voici un petit script avec quelques explications pour changer le répertoire de mysql (datadir) sous debian wheezy.

Explications :

La ligne permettant de changer le répertoire des données de mysql est la ligne contenant datadir dans le fichier /etc/mysql/my.cnf

datadir  = /app/mysql

Une fois cette ligne modifiée, il faut réinstaller la base de données. Redémarrer simplement mysql ne fonctionne pas. La commande mysql_install_db est prévue à cet effet. Elle crée les fichiers et dossiers nécessaires dans le nouveau répertoire.

Après cela, le redémarrage de mysql fonctionnera. Cependant, un message d’erreur apparaitra. La réinstallation de la base n’a pas conservé l’utilisateur dédié à la maintenance

Message d’erreur au lancement de mysql

ERROR 1045 (28000): Access denied for user 'debian-sys-maint'@'localhost' (using password: YES)

La solution consiste à créer l’utilisateur demandé en récupérant le mot de passe dans le fichier /etc/mysql/debian.cnf

Script shell :

#!/bin/bash
/etc/init.d/mysql stop
# Install database in directory configured in my.cnf
mysql_install_db
# Restart mysql
/etc/init.d/mysql start
#Get password from config file
MYSQL_PWD_DEBIAN=`grep password /etc/mysql/debian.cnf | cut -d= -f2 | head -n 1 | tr -d ' '`
echo "Password for debian-sys-maint = $MYSQL_PWD_DEBIAN"
# Create debian user
mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'debian-sys-maint'@'localhost' IDENTIFIED BY '$MYSQL_PWD_DEBIAN';"

Spring batch exception

Il est possible de configurer un batch spring pour ne pas s’arrêter lorsqu’il rencontre un certain type d’exception en paramétrant les skyppables exceptions.spring batch chunk

Exception dans un reader

Non skyppable exception
Le batch s’arrête avec un statut en erreur.

Skyppable exception
J’ai fait le test en levant une exception dans un rowmapper.

  • la ligne ayant générée l’exception n’est pas traitée
  • les autres lignes sont traitées normalement

Exception dans un writer

Non skyppable exception
Le batch s’arrête avec un statut en erreur.

Skyppable exception
Le writer traite une ensemble d’items en fonction du paramètre commit-interval.
Lorsqu’une exception skyppable est levée dans un writer, le traitement par lot du writer s’arrête et la transaction est rollbackée.
Chaque élément du lot va être retraité séparément pour permettre d’exclure le fautif. Pour cela, le writer est ré-exécuté et reçoit les items un à un (comportement équivalent à commit-interval= »1″).
Ceci se produit même si le writer traite qu’un seul élément (commit-interval= »1″ par exemple) ou un seul élément à traiter dans le batch.

Photos Bayonne

Forêt

2014-07-16 - Foret (8)

 2014-07-16 - Foret (5)

Cache HTTP

Cache

Pour cacher, il est important de spécifier au moins les headers suivants :

  • Expires ou Cache-Control: max-age. Ceci permet au navigateur de connaître l’instant auquel il doit effectuer une requête au serveur.
  • Last-Modified ou Etag. Permet d’effectuer une requête conditionnelle.

 Header Etag

L’Etag est un identifiant assigné par le serveur à une ressource. La norme HTTP 1.1 ne définit pas comment le construire mais il est généralement calculé grâce à une fonction de hashage. Il représente en fait un checksum de la ressource. Si la ressource change alors l’ETAG sera différent.

L’Etag en lui même ne véhicule aucune information permettant au client (user agent) de déterminer s’il doit effectuer une nouvelle requête pour obtenir une nouvelle version de la ressource. Avec l’Etag comme seule information, le client effectuera dans tous les cas une requête vers le serveur. Le serveur confrontera l’Etag de la requête avec celui de a ressource pour renvoyer un code de retour 200 ou 304 (Etag identique). Pour empêcher le navigateur d’effectuer une requête à chaque demande il faut positionner le header Expires ou Cache-Control: max-age.

 Calcul de l’Etag

Bien que la spécification HTTP 1.1 n’indique en rien la manière de générer l’Etag, les serveurs utilisent généralement une fonction de hashage. La valeur hashée peut être :

  • le contenu de la ressource
  • la date de modification
  • un nombre de révision

Exemple d’implémentation :

  • Filtre de servlet calculant l’Etag sur le contenu de la réponse
  • FileETag directive d’apache pour les fichiers statiques

 Header Last-Modified

Date de dernière modification de la ressource renvoyée par le serveur. Utilisé pour les ressources statiques.

Etag ou Last-Modified ?

Les ressources statiques peuvent donc se voir affecter un Etag et/ou un header Last-Modified tandis que les ressources dynamiques se veront plus généralement affecter un Etag. En effet, de par sa nature, l’Etag peut être utilisé pour les ressources statiques et dynamiques (hash du contenu ou hash d’un attribut du fichier). La date de modification est plus difficile à calculer pour une page dynanique (ensemble de requêtes SQL et de HTML) que pour un simple fichier (attribut mtime). C’est pour cela que les ressources dynamiques portent principalement des Etag et que les ressources statiques portent le header Last-Modified.

Code de retour 304

La réponse 304 signifie que la copie de la ressource que dispose le client n’a pas été modifié depuis sa dernière demande. Le navigateur réutilise alors sa version de la ressource. Cela permet de ne pas renvoyer le contenu de la ressource ce qui minimise minimise le temps d’affichage.

Requête conditionnelle

Lorsque le cache de la ressource est expiré, le navigateur envoie une requête conditionnelle. La requête dispose des headers suivants :

  • If-Modified-Since : contient la date de dernière modification de la ressource locale
  • If-None-Match : etag de la copie locale

Une fois que le serveur a reçu la requête, il détermine si la ressource est périmée. Si c’est le cas, le contenu de la ressource est renvoyé au client avec un code HTTP 200. Le navigateur utilise alors le corps de la réponse et la cache à nouveau.

Header Cache-Control

Ce header est à la fois un header de requête et de réponse.

Requête

Si un navigateur envoie une requête comportant le header Cache-Control: max-age=0 (aka end-to-end revalidation) alors tous les caches entre le navigateur et le serveur revalideront la ressource. Pour cela le navigateur envoie également les headers permettant d’effectuer une requête conditionnelle (If-Modified-Since et If-None-Match). La réponse peut être un code 304.

Si le navigateur envoie une requête comportant le header Cache-Control : no-cache (aka end-to-end reload) alors le serveur ne doit pas renvoyer une copie de la ressource.

Par exemple, Firefox envoie le header « Cache-Control : max-age=0 » lors d’un F5 et le header « Cache-Control : no-cache » lors d’un ctrl+F5

Réponse

  • no-cache : Le navigateur doit revalider la ressource à chaque appel
  • max-age : Durée maximum de rétention de la ressource dans le cache navigateur. Cette directive outrepasse l’en-tête Expires
  • no-store : le cache navigateur ne doit pas stocker la ressource en local

Header Expires

Date à laquelle le cache expire. Header de la norme HTTP 1.0 renvoyé par le serveur. Sur les navigateurs modernes « cache control » prévaut.

Quand le cache a expiré le navigateur envoie une requête conditionnelle au serveur avec les headers If-Modified-Since et If-None-Match.

 

Enchainement des requêtes

diagramme sequence http requete1 Le navigateur ne connaît pas la ressource. Il effectue une requête GET pour l’obtenir. request1

2Le serveur renvoie la ressource (HTTP 200) avec des headers de cache.

  • Le header Cache-Control indique que la ressource est cachée 1h (max-age=3600)
  • Le header Expires est également positionné est indique bien que la ressource doit être considérée comme périmée dans une heure. Le header expire est redondant avec Cache-Control
  • La date de dernière modification et un Etag sont renvoyés permettant d’effectuer une requête conditionnelle à l’expiration du cache

response23Le cache local du navigateur est arrivé à expiration. Il demande au serveur si la ressource qu’il possède est toujours valide. Pour cela il effectue une requête conditionnelle.request3

4La ressource n’ayant pas été modifiée, le serveur renvoie un code HTPP 304 autorisant le navigateur à réutiliser sa copie locale. La ressource est de nouveau valide durant 1 heure. response 4

Sources

http://blogs.telerik.com/fiddler/posts/12-11-05/understanding-http-304-responses
http://en.wikipedia.org/wiki/HTTP_ETag
http://www.baeldung.com/2013/01/11/etags-for-rest-with-spring/
http://www.mobify.com/blog/beginners-guide-to-http-cache-headers/
http://stackoverflow.com/questions/10314174/difference-between-pragma-and-cache-control-headers
http://stackoverflow.com/questions/998791/if-modified-since-vs-if-none-match
http://stackoverflow.com/questions/1046966/whats-the-difference-between-cache-control-max-age-0-and-no-cache
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4

Couleur dans le shell linux

Voici la configuration que j’utilise pour colorer le promp de mes debian wheezy. Le prompt sera bleu pour un utilisateur et rouge en tant que root.

prompt

Etape 1 : commenter toutes les références à PS1 dans le fichier ~/.bashrc de l’utilisateur
Etape 2 : ajouter à la fin du fichier /etc/bash.bashrc les lignes suivantes :

if [ $EUID == 0 ] ; then
        PS1='\[\033[01;31m\]\u@\h\[\033[01;31m\] \W \$\[\033[00m\] '
else
        PS1='\[\033[01;34m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] '
fi