<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Artisan Numérique</title>
  <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1609"/>
  <link rel="self" type="application/atom+xml" href="http://artisan.karma-lab.net/node/1609/atom/feed"/>
  <id>http://artisan.karma-lab.net/node/1609/atom/feed</id>
  <updated>2008-08-06T17:56:59+02:00</updated>
  <entry>
    <title>Bash, les blocs de code et les variables</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1609" />
    <id>http://artisan.karma-lab.net/node/1609</id>
    <published>2008-08-06T14:23:36+02:00</published>
    <updated>2008-08-06T17:56:59+02:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Bash" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[<p>
   Les langages de Shell, dont 
  <a target='_blank' href='http://fr.wikipedia.org/wiki/Bash'>
  Bash
  </a> n'est que la version GNU, sont de vénérables ancêtres aussi vieux que la ligne de commande elle-même. Le Korn Shell ou 
  <a target='_blank' href='http://fr.wikipedia.org/wiki/ksh'>
  ksh
  </a> par exemple a prés de 30 ans. </p>
   <p>Suivant la croyance que tout ce qui est nouveau est mieux, Bash, et ses confrère, est souvent relégué au rang d'antiquité bordélique et peu puissante. Mais lorsqu'il est mieux connu, BASH est en réalité assez cohérent et permet de scripter à une vitesse étonnantes des choses très évoluées pour le nombre de lignes de code produites. Ce n'est pas un hasard si le coeur du démarrage de Linux n'est à peu prés écrit qu'en Bash. </p>
   <p>Le but de ce tutoriel n'est pas d'expliquer comment fonctionne BASH. Il y a d'excellent tutoriels qui font cela très bien. Mon idée est plus de documenter dans la langue de Molière certains aspects plus pointus de ce langage et en l'occurrence l'utilisation des blocs de codes, des fonctions et des variables. 
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
   Les langages de Shell, dont 
  <a target='_blank' href='http://fr.wikipedia.org/wiki/Bash'>
  Bash
  </a> n'est que la version GNU, sont de vénérables ancêtres aussi vieux que la ligne de commande elle-même. Le Korn Shell ou 
  <a target='_blank' href='http://fr.wikipedia.org/wiki/ksh'>
  ksh
  </a> par exemple a prés de 30 ans. </p>
   <p>Suivant la croyance que tout ce qui est nouveau est mieux, Bash, et ses confrère, est souvent relégué au rang d'antiquité bordélique et peu puissante. Mais lorsqu'il est mieux connu, BASH est en réalité assez cohérent et permet de scripter à une vitesse étonnantes des choses très évoluées pour le nombre de lignes de code produites. Ce n'est pas un hasard si le coeur du démarrage de Linux n'est à peu prés écrit qu'en Bash. </p>
   <p>Le but de ce tutoriel n'est pas d'expliquer comment fonctionne BASH. Il y a d'excellent tutoriels qui font cela très bien. Mon idée est plus de documenter dans la langue de Molière certains aspects plus pointus de ce langage et en l'occurrence l'utilisation des blocs de codes, des fonctions et des variables. 
</p>
<!--break-->

	<a name='chapter_1'></a>
  <h2>Les blocs</h2>
	
<p>
   Tout le monde connaît les fonctions en BASH :
   
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co0"># définition de ma_fonction</span><br />
&nbsp;<span class="kw1">function</span> ma_fonction <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/ls"><span class="kw2">ls</span></a> <span class="sy0">/</span>sys<br />
&nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/ls"><span class="kw2">ls</span></a> <span class="sy0">/</span>proc<br />
&nbsp;<span class="br0">&#125;</span><br />
<br />
&nbsp;<span class="co0"># appel de la fonction</span><br />
&nbsp;ma_fonction <span class="sy0">|</span> <a target="blank" href="http://pwet.fr/man/linux/commandes/grep"><span class="kw2">grep</span></a> cpu
  </div>
  
  </div>
</p>
<p>
    Une fonction fonctionne à peu prés comme une commande de base ou un sous-script. On peut lui passer des paramètres (<kbd>$1</kbd>, <kbd>$2</kbd>...), elle a une valeur de retour avec le mot clef <kbd>return</kbd> à la place du <kbd>exit</kbd>. On peut même utiliser avec elle les redirections, pipes compris comme nous le voyons dans l'exemple. En somme la seule différence entre une fonction et un script ou une commande externe, c'est qu'il n'y a pas création du nouveau processus. 
</p>
<p>
   Maintenant ce que l'on sait moins c'est qu'une fonction en Bash est en réalité un cas particulier d'un concept plus large, celui de bloc de code. Il est ainsi possible de créer des fonctions qui n'ont pas de nom au sein d'un script. Ainsi le code précédent peut s'écrire de la manière suivante :
   
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp;<a target="blank" href="http://pwet.fr/man/linux/commandes/ls"><span class="kw2">ls</span></a> <span class="sy0">/</span>sys<br />
&nbsp; &nbsp; &nbsp;<a target="blank" href="http://pwet.fr/man/linux/commandes/ls"><span class="kw2">ls</span></a> <span class="sy0">/</span>proc<br />
<span class="br0">&#125;</span> <span class="sy0">|</span> <a target="blank" href="http://pwet.fr/man/linux/commandes/grep"><span class="kw2">grep</span></a> cpu
  </div>
  
  </div>
</p>
<p>
  Autre exemple pratique, d'utilisation d'un bloc pour conditionner l'exécution d'une série de commande au bon déroulement d'une première commande :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; &nbsp; &nbsp; command1 <span class="sy0">&amp;&amp;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sous-commande1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sous-commande2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;...<br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
   En somme un bloc est une fonction anonyme, qui s'exécute tout de suite, qui ne peut avoir de passage paramètre  (<kbd>$1</kbd>, <kbd>$2</kbd>...) et ne peut renvoyer de code de retour (<kbd>return</kbd>). Tout le reste est possible. Maintenant comme une fonction est un bloc, la logique nous souffle que s'il est possible de mettre un bloc dans une fonction, il doit aussi être possible de placer une fonction dans une autre fonction :
   
  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">function</span> test1 <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">function</span> test2 <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Je suis dans test2&quot;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Je suis dans test1&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;test2 &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;test1
  </div>
  
  </div> 
</p>
<p>
  Et effectivement cela fonctionne très bien, de même que mettre une fonction dans un bloc anonyme... Maintenant on peut se demander quelle sont les règles de visibilités sur les fonctions. Deux fonctions dans deux bloc distinct peuvent t-elles s'appeler ? La réponse à cette question passe par une petite manipulation :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">function</span> test2 <span class="br0">&#123;</span><br />
&nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Je suis dans test2&quot;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
<span class="br0">&#125;</span><br />
<span class="kw1">set</span> <span class="sy0">|</span> <a target="blank" href="http://pwet.fr/man/linux/commandes/grep"><span class="kw2">grep</span></a> test2
  </div>
  <div class='caption'>test.sh</div>
  </div>
</p>
<p>
  Si on exécute ce script cela nous donne
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='command'><span class='prompt'>gaston$</span>./test?sh</div><div class='result'>test2 ()</div><div class='result'>echo "Je suis dans test2"</div><div class='command'><span class='prompt'>gaston$</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>
<p>
   Ainsi une fonction n'est rien d'autre qu'une variable. Du coup, la réponse à notre question réside dans les régles de visibilités qui leur sont associées. 
</p>

<p>
  Pour terminer sur les blocs de code, sachez que TOUT n'est que block de code. Et une commande seule est un bloc dont les accolades ont été rendues optionnelles. Ainsi les deux syntaxe suivantes sont équivalentes :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw3">echo</span> -e <span class="st0">&quot;coucou<span class="es0">\n</span>salut<span class="es0">\n</span>&quot;</span> <span class="sy0">|</span> <a target="blank" href="http://pwet.fr/man/linux/commandes/grep"><span class="kw2">grep</span></a> <span class="st0">&quot;coucou&quot;</span><br />
<br />
<span class="co0"># est équivalent à </span><br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="kw3">echo</span> -e <span class="st0">&quot;coucou<span class="es0">\n</span>salut<span class="es0">\n</span>&quot;</span> <br />
<span class="br0">&#125;</span> <span class="sy0">|</span> <span class="br0">&#123;</span><br />
&nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/grep"><span class="kw2">grep</span></a> <span class="st0">&quot;coucou&quot;</span><br />
<span class="br0">&#125;</span>
  </div>
  
  </div> 
</p>


	<a name='chapter_2'></a>
  <h2>Visibilité des variables</h2>
	
<p>
	En Bash,  les variables d'environnement font parti de l'espace de travail du processus. Par défaut, les variables d'un processus ne sont pas visible par les processus engendrés. Pour que cela puisse ce faire, il faut marquer les variables avec la commande  <kbd>export</kbd>. En revanche, un processus fils ne peut jamais modifier les variables du processus parent. Ainsi si l'on a un premier script  :
	
  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">echo</span> <span class="st0">&quot;V1 = $V1&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">echo</span> <span class="st0">&quot;V2 = $V2&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="re2">V2=</span><span class="st0">&quot;valeur torpillée&quot;</span>
  </div>
  <div class='caption'>script1.sh</div>
  </div>
</p>
<p>
  Et un second qui définit deux variables, dont une est marquée par <kbD>export</kbd> :
	
  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; &nbsp; &nbsp; &nbsp;<span class="re2">V1=</span><span class="st0">&quot;Valeur 1&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="re2">V2=</span><span class="st0">&quot;valeur2&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">export</span> V2<br />
&nbsp; &nbsp; &nbsp; &nbsp;.<span class="sy0">/</span>script1.<a target="blank" href="http://pwet.fr/man/linux/commandes/sh"><span class="kw2">sh</span></a><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="co0"># la valeur est inchangée malgrès l'action de script1.sh</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">echo</span> <span class="st0">&quot;V2 = $V2&quot;</span>
  </div>
  <div class='caption'>script2.sh</div>
  </div>
</p>
<p>
  A l'exécution du second script nous voyons bien que V1 n'est pas renseigné mais que V2 l'est. En revanche, nous constatons bien que le sous-script n'a pas réussi à torpiller la valeur de la variable parent. Les données peuvent donc "descendre" mais pas "remonter".</p>
  <p>
  Maintenant qu'en est-il pour une fonction ? Et bien comme c'est une variable, les mêmes règles s'appliquent : elle ne sera pas visible par les processus fils. Pour qu'elle le soit, il faut l'exporter. Si si, avec un paramètre magique en plus ça fonctionne très bien : <kbd>export <b>-f</b> ma_fonction</kbd>.  
</p>

<p>
   Maintenant que nous voyons bien les régles entre le processus courant et ceux engendrés, comment cela se passe-t-il pour les blocs et les fonctions ? Pour tester cela, nous pouvons modifier un peu notre <kbd>./script2.sh</kbd> en supprimant la ligne <kbd>export V2</kbd> et en lançant le script de manière un peu différente, par un <kbd>source ./script1.sh</kbd>. Et là... nos deux variables sont renseignées sans qu'aucune ne soit exportée. La "magie" réside dans le mot clef <kbd>source</kbd>. Lorsque l'on "source" un script, bash le charge... dans un bloc. On en déduit que les règles de visibilité changent un peu lorsque l'on reste dans le même processus. A noter avant d'aller plus loin que la syntaxe <kbD>source script</kbd> est équivalente à la plus connue <kbd>. ./script</kbd> (attention au premier point, suivi d'un espace). 
</p>
<p>
  La régle dans les blocs d'un même processus est donc que l'inverse de celle qui nous obligeait à utiliser <kbd>export</kbd> : les variables (et donc les fonctions) créées dans un bloc sont visibles partout ailleurs. Pour changer ce comportement, vous pouvez marquer, uniquement dans un bloc "fonction", les variables comme <kbd>local</kbd>. Attention cependant, ce changement de visibilité interdit juste la variable d'être vu des blocs parents, elle ne la cache pas des blocs enfants. 
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; &nbsp; &nbsp; <span class="kw1">function</span> <span class="kw3">test</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co0"># une variable déclarée comme locale</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">local</span> <span class="re2">v1=</span><span class="nu0">12</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co0"># un bloc enfant...</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;la variable reste visible ici : $v1&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw3">test</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Mais là, elle est invisible : $v1&quot;</span>
  </div>
  
  </div> 
</p>

<div class='inline-box attention'>
   Un cas bien tordu est celui d'un bloc de code (fonction ou pas) qui est pipé sur un second bloc de code. Dans la mesure où le pipe induit la création d'un sous-processus dans lequel est exécuté le code du second bloc, c'est la règle de visibilité entre scripts qui s'applique, pas celle des variables internes. Du coup le code suivant ne marchera jamais  et la valeur <kbd>v1</kbd> ne sera pas modifiée.
   
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re2">v1=</span><span class="st0">&quot;V1&quot;</span><br />
<span class="kw3">echo</span> <span class="st0">&quot;Valeur modifiée&quot;</span> <span class="sy0">|</span> <a target="blank" href="http://pwet.fr/man/linux/commandes/read"><span class="kw2">read</span></a> v1 <br />
<span class="kw3">echo</span> <span class="re1">$v1</span>
  </div>
  
  </div>
</div>

<p>
  Pour terminer sur la visibilité, il nous reste une possibilité à explorer. Celle de rendre une variable accessible pour un bloc seulement. Tout le monde connais la syntaxe suivante :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re2">variable=</span>valeur commande
  </div>
  
  </div>
</p>
<p>
   L'idée sous-jacente est qu'une copie des variables est faite à l'arrivée sur cette ligne et que la variable <kbd>variable</kbd> y est insérée. Cette copie est ensuite passée à la commande. Ainsi la variable en question n'est visible QUE de cette commande. Et bien sur la même chose est possible avec un bloc de code, mais uniquement de type "fonction" :
   
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">function</span> <span class="kw3">test</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">echo</span> <span class="st0">&quot;v1 : $v1&quot;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="re2">v1=</span><span class="st0">&quot;salute&quot;</span> &nbsp;<span class="kw3">test</span><br />
<span class="kw3">echo</span> <span class="st0">&quot;v1 : $v1&quot;</span>
  </div>
  
  </div>
</p>

<H2>Référencement indirect</H2>
<p>
   Maintenant que nous avons une bonne compréhension des variables, voyons comment aller plus loin en y accédant par adressage indirecte. L'idée est de disposer d'une variable qui contient le nom d'une autre variable et de pouvoir lire et changer la valeur de cette seconde variable. Le tout est de connaître la syntaxe :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re2">V1=</span><span class="nu0">12</span><br />
<span class="kw3">echo</span> <span class="st0">&quot;Lecture directe : $V1&quot;</span> <br />
<span class="re2">nom_de_variable=</span><span class="st0">&quot;V1&quot;</span><br />
<span class="kw3">echo</span> <span class="st0">&quot;Lecture indirecte : ${!nom_de_variable}&quot;</span>
  </div>
  
  </div>
</p>
<p>
   Maintenant voyons comment écrire de manière indirecte en utilisant la fonction bien pratique <kbd>eval</kbd>
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw3">eval</span> <span class="co1">${nom_variable}</span>=valeur
  </div>
  
  </div>
</p>



	<a name='chapter_3'></a>
  <h2>Un peu d'introspection</h2>
	
<p>
  Alors maintenant nous savons adresser des variables de manière indirecte. Vu que les fonctions sont elles aussi des variables, il doit y avoir moyen de faire avec elles la même chose. Commençons par écrire une fonction qui vérifie que la fonction dont le nom sera passé en paramètre existe. Pour cela nous utilisons la fonction <kbd>type</kbd>. Cette dernière utilisée avec le paramètre <kbd>-t</kbd> suivi d'un nom de variable, nous renvoie une chaîne indiquant le type de cette variable : <kbd>alias</kbd>, <kbd>keyword</kbd>, <kbd>builtin</kbd>, <kbd>file</kbd> ou <kbd>function</kbd>. C'est le dernier cas qui nous intéresse :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; <span class="kw1">function</span> <span class="kw3">test</span> <span class="br0">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Hello World&quot;</span> <br />
&nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; <span class="kw1">function</span> teste <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="re2">t=</span>$<span class="br0">&#40;</span><span class="kw3">type</span> -t $<span class="nu0">1</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re4">$?</span> -ne <span class="st0">&quot;0&quot;</span> <span class="br0">&#93;</span> ; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;'$1' est introuvable&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="st0">&quot;$t&quot;</span> == <span class="st0">&quot;function&quot;</span> <span class="br0">&#93;</span> ; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;'$1' est une fonction&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;'$1' n'est pas un fonction, c'est un $t&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">fi</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span><br />
&nbsp; <span class="br0">&#125;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
<br />
teste <span class="st0">&quot;test&quot;</span><br />
teste <span class="st0">&quot;if&quot;</span><br />
teste <span class="st0">&quot;test1&quot;</span><br />
teste <span class="st0">&quot;./test.sh&quot;</span>
  </div>
  
  </div>
</p>
<p>
  Ce qui nous donne à l'exécution 
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='command'><span class='prompt'>gaston$</span>./test.sh</div><div class='result'>'test' est une fonction</div><div class='result'>'if' n'est pas une fonction, c'est un keyword</div><div class='result'>'test1' est introuvable</div><div class='result'>'./test.sh' n'est pas une fonction, c'est un file</div><div class='command'><span class='prompt'>gaston$</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>

<p>
  Grâce à cela nous pouvons savoir si une fonction existe et même récupérer la liste des fonctions existantes en parcourant la liste des variables (genre renvoyée par <kbd>set</kbd>). Mais cela ne servirait pas à grand chose si l'on ne pouvait pas exécuter de manière indirecte une fonction :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re2">nom_fonction=</span>test<br />
<span class="re1">$nom_fonction</span> arguments
  </div>
  
  </div>
</p>
<p>
  Alors quel est l'intérêt de cette méthode ? Simplement de pouvoir construire des "hooks". Des hooks sont des fonctions qui son exécutées pour modifier un comportement si elles existent. Nous pouvons donc faire des petits plugins en bash très facilement. Pour cela écrivons le code suivant :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">function</span> callback<br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="re2">name=</span>$<span class="nu0">1</span><br />
&nbsp; <span class="kw3">shift</span><br />
&nbsp; <span class="re2">kind=</span>$<span class="br0">&#40;</span><span class="kw3">type</span> -t <span class="st0">&quot;$name&quot;</span><span class="br0">&#41;</span><br />
&nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="st0">&quot;$kind&quot;</span> == <span class="st0">&quot;function&quot;</span> <span class="br0">&#93;</span> ; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp;<span class="re1">$name</span> <span class="re4">$*</span><br />
&nbsp; &nbsp; &nbsp;<span class="kw3">return</span> <span class="nu0">0</span><br />
&nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; <span class="kw3">return</span> <span class="nu0">1</span><br />
&nbsp; <span class="kw1">fi</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="re2">plugins=</span>$<span class="br0">&#40;</span><a target="blank" href="http://pwet.fr/man/linux/commandes/ls"><span class="kw2">ls</span></a> .<span class="sy0">/</span>dossier_plugins<span class="sy0">/*</span>.plugin<span class="br0">&#41;</span><br />
<br />
<span class="kw1">for</span> plugin <span class="kw1">in</span> <span class="re1">$plugins</span> ; <span class="kw1">do</span><br />
&nbsp; <span class="co0"># on sauve le nom de fichier</span><br />
&nbsp; <span class="re2">file=</span><span class="re1">$plugin</span><br />
&nbsp; <span class="co0"># on supprime le dossie</span><br />
&nbsp; <span class="re2">plugin=</span>$<span class="br0">&#40;</span><a target="blank" href="http://pwet.fr/man/linux/commandes/basename"><span class="kw2">basename</span></a> <span class="re1">$plugin</span><span class="br0">&#41;</span><br />
&nbsp; <span class="co0"># on supprime l'extension</span><br />
&nbsp; <span class="re2">plugin=</span><span class="co1">${plugin%.*}</span><br />
&nbsp; <span class="co0"># on source le script</span><br />
&nbsp; . <span class="re1">$file</span><br />
&nbsp; <span class="co0"># on cherche à exécuter la fonction hook_description si elle existe</span><br />
&nbsp; <span class="re2">description=</span>$<span class="br0">&#40;</span>callback <span class="co1">${plugin}</span>_description<span class="br0">&#41;</span><br />
<br />
&nbsp; <span class="co0"># si le hook s'est bien exécuté...</span><br />
&nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re4">$?</span> -eq <span class="nu0">0</span> <span class="br0">&#93;</span> ; <span class="kw1">then</span><br />
&nbsp; &nbsp; <span class="co0"># on exécute la fonction permettant de récupérer la valeur</span><br />
&nbsp; &nbsp; <span class="re2">value=</span>$<span class="br0">&#40;</span>callback <span class="co1">${plugin}</span>_execute<span class="br0">&#41;</span><br />
<br />
&nbsp; &nbsp; <span class="co0"># affichage</span><br />
&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;$description = $value&quot;</span><br />
&nbsp; <span class="kw1">fi</span><br />
<span class="kw1">done</span> &nbsp;
  </div>
  <div class='caption'>lire_capteurs.sh</div>
  </div>  
</p>
<p>
   Maintenant, il suffit de créer un sous dossier <kbd>dossier_plugins</kbd> et d'y mettre par exemple 
   
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">function</span> hd_occupation_description <span class="br0">&#123;</span><br />
&nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Taux d'occupation du disque&quot;</span>;<br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw1">function</span> hd_occupation_execute <span class="br0">&#123;</span><br />
&nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/df"><span class="kw2">df</span></a> <span class="sy0">/</span>dev<span class="sy0">/</span>sda1 <span class="sy0">|</span> <a target="blank" href="http://pwet.fr/man/linux/commandes/grep"><span class="kw2">grep</span></a> <span class="sy0">/</span>dev<span class="sy0">/</span>sda1 <span class="sy0">|</span> <a target="blank" href="http://pwet.fr/man/linux/commandes/awk"><span class="kw2">awk</span></a> <span class="st0">'{print $5}'</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>hd_occupation.plugin</div>
  </div>
</p>
<p>
  Encore un autre pour la température cette fois :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">function</span> hd_temp_description <span class="br0">&#123;</span><br />
&nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Température du disque&quot;</span>;<br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw1">function</span> hd_temp_execute <span class="br0">&#123;</span><br />
&nbsp; hddtemp -n <span class="sy0">/</span>dev<span class="sy0">/</span>hda<br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>hd_temp.plugin</div>
  </div>
</p>
<p>
  Voilà, maintenant nous pouvons lancer notre script
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='command'><span class='prompt'>gaston$</span>./lire_capteurs</div><div class='result'>Taux d'occupation du disque = 64%</div><div class='result'>Température du disque = 41</div><div class='command'><span class='prompt'>gaston$</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>

<p>
  En quelques lignes de bash, nous avons un "nagios du pauvre" qui s'étend de manière très simple en ajoutant des plugins dans le dossier <kbd>./dossier_plugins</kbd>.  
</p>


	<a name='chapter_4'></a>
  <h2>Conclusion</h2>
	
<p>
  Il ne s'agit pas de construire d'énormes applications en bash plus que de l'utiliser pour ce qu'il est, à savoir le plus efficace moyen de commander un système unix. Un programme écrit en python, perl ou ruby sera sans nul doute plus robuste ou offrira plus de fonctionnalités, mais la compacité de la ligne de commande permet à bash de battre des records de vitesse pour des tâches simples et répétitives. De plus son côté "standard" fait que n'importe quelle distribution sera capable de manger du bash, ce qui est un gros plus de portabilité. 
</p>    ]]></content>
  </entry>
</feed>
