Bon voici un billet sans doute “technique” pour qui n’en fait pas du tout mais il est assez simple, si, si promis, et représentatif d’un problème courant sur les serveurs, à savoir qu’un programme vérifie à son lancement qu’il n’est pas déjà lancé afin d’éviter des collisions dans le traitement de son activité.
L’idée est donc de compter le nombre d’instances et de prendre nos décisions sur cette base et c’est LA ligne en charge de cette activité que je propose pour analyse.
Il m’a été inspiré par les deux heures de parlottes dans mon open-space d’autres personnes dont j’ai fini par voir un peu marre et que j’ai donc aidées à résoudre ce problème.
Pour les fans du docteur Layton, sortez votre haut de forme !
Filtres
En Unix, il existe de nombreux programmes que l’on nomme filtre car ils n’ont d’autre usage que de “tamiser” un contenu selon nos besoins. Donc réellement leurs actions sur le système sont nulles, elles ne changent pas la résolution de l’affichage à l’écran ni ne permettent de récupérer les “cables” américains… tout au plus de les trier ;)
grep
Un des plus fameux filtres, il permet de rechercher une séquence de caractère paramétrable et de signaler son absence, sa présence, éventuellement son nombre d’occurrence, ça dépend des options souhaitées. Un exemple, si grep recherchait le mot “chat” dans le fichier fic1 donc le contenu serait le suivant:
Le chat mange des os
Le chien mange des poissons
grep me retournerait par défaut :
# grep chat fic1
Le chat mange des os
L’option ‘-v‘, qui apparait dans la seconde occurrence, permet elle de filtrer à l’envers, à savoir ne retenir que les lignes où la chaîne n’apparait. Dans le cas de fic1 et de la recherche précédente, nous aurions:
# grep -v chat fic1
Le chien mange des poissons
wc
Non pas le canard, encore un autre filtre qui signifie en fait “Word Count” et donc compte les mots, les caractères et les lignes. L’option ‘-l‘ lui demande de n’indiquer que le nombre de lignes lues. Sur notre fic1, cela donnerait :
# wc -l fic1
2 /tmp/fic1
Commandes
Là, il s’agit de programme qui ont une réelle capacité à obtenir des informations du système ou de le modifier. Ici, une seule suffit au vu du but annoncé, à savoir ce qui est en train de tourner !
ps
Là encore, cette commande a une signification à savoir “process status”. C’est un peu comme le gestionnaire des tâches de windows, on sait ce qui fonctionne, qui le fait fonctionner, etc
Les options ici sont assez simples ‘-f‘ pour full afin que la commande nous offre un listing complet et ‘-u‘ pour limiter néanmoins ce listing à l’utilisateur root, à savoir l’administrateur système.
Shell
Bon, tous nos commandes et nos filtres, ne vivent pas dans le néant et ce qui permet de les saisir, c’est ce qu’on appelle le shell, littéralement une coquille. Dans le monde Unix IBM, par défaut, c’est un shell plaisamment appelé Korn Shell 88, vous pouvez headbanger.
Ce shell a la gentillesse d’offrir la gestion des variables, à savoir associer un identifiant à une valeur, les pipes, à savoir faire de la plomberie pour brancher une suite de programmes entre eux, et la substitution de commandes avec $(), qui permet de remplacer le contenu entre les parenthèses par les valeurs retournées par les programmes qu’elle contient. Mais développons brièvement.
Variables
C’est un incontournable en programmation impérative, on donne des noms plus ou moins clairs à ces variables et on leur assigne une valeur. Selon le langage, on peut avoir à se soucier du typage, à savoir si notre variable doit, par exemple contenir, un nombre ou un caractère mais le shell est permissif sur ce point.
L’affectation du contenu d’une variable se fait avec le signe “=“. Notre billet ici présent raconte donc l’histoire de l’affectation d’une certaine valeur à ‘nb‘.
Pipes
On ne rigole pas…
Ce concept au nom amusant est une évolution majeure du shell Unix, même si celle-ci date, et permet de faire communiquer des programmes entre eux sans devoir passer par de l’écriture sur disque. Si nous repensons à nos filtres, qui permettent donc de filtrer un contenu, il y a donc une entrée et une sortie. Le pipe fait que la source est le programme situé avant et que la sortie se fait sur le programme d’après.
La conséquence est que l’ensemble des commandes chaînées s’exécute quasi-simultanément pour profiter de ce mécanisme.
Notre chaînage assure donc que la liste des processus sera filtrée 3 fois (grep/grep/wc), et que le premier grep ne s’arrêtera pas avant que ps n’ait terminé, ni que le second grep ne s’arrêtera avant que le premier grep n’est terminé, je vous laisse déduire pour wc ;)
Substitution de commandes
Conclusion logique, nous cherchons à allouer à ‘nb‘ une valeur, à savoir celle obtenue par la succession de nos commandes que nous aurons permis les fameux pipes et cette magique substitution de commandes.
Pour réaliser cette action, les commandes destinées à être substituées sont lancées dans un sous-shell qui porte le nom du shell parent.
And now…
Bien, cette ligne apparait donc dans le script mon_programme dont nous souhaitons, rappelons le, qu’il s’assure qu’une instance de lui même ne s’exécute pas déjà.
Maintenant, le ver est déjà dans le fruit, la valeur retournée ne sera pas la bonne. Quant au pourquoi, je laisse mes amiEs geeks cogiter un peu, proposer des réponses, sous 2-3 jours je dirais tout le mal que je pense de cette façon de faire ;)