====== Le système d'entrées/sorties ====== ===== Introduction ===== Cette petite bibliothèque de fonctions permet de gérer finement l'affichage et la trace de cet affichage en log, et ce de manière intuitive. On peut donc la voir comme une //super commande echo//. On trouvera son utilisation intéressante dès que l'on aura besoin d'avoir une trace de ce qui a été affiché en sortie de commandes exécutée (pas forcément affiché à l'écran) et/ou un affichage en couleur en fonction du type de message à afficher (erreur, avertissement, debuggage, etc..). ===== Principe de fonctionnement ===== ====Généralités==== Il s'agit d'un module que l'on paramètre en faisant appel à plusieurs de ses fonctions, puis que l'on utilise. Bien sûr, il est possible de modifier les paramètres en cours d'utilisation, et même de sauver l'ensemble de la configuration temporairement, le temps par exemple de changer de contexte d'utilisation. Pour cela, **nio** (**N**asgaïa **I**nput/**O**utput) dispose de plusieurs variables internes, qui sont volontairement //mal nommées// (voir par là des noms un peu longs), car l'utilisateur n'a normalement pas besoin de s'y référer directement (le module a été pensé de cette façon). ====L'affichage et le log==== L'une des principale caractéristiques de ce module est de permettre une gestion du contenu affiché à l'écran, et parallèlement loggué dans un fichier de trace. En effet, suivant le type d'information à afficher/logguer, il pourait être intéressant d'éviter la sortie console ou de tracer celle d'une commande particulière dans un fichier à part. **nio** permet de gérer à la fois pour la sortie écran et le fichier de log les types de messages suivants : * **error** - erreurs (//error//), le plus souvent mettant fin au script, mais pas nécessairement * **warn** - avertissements (//warning//), indique quelque chose d'important * **info** - informations (//informations//), le type normal, pour informer l'utilisateur de ce qu'il se passe * **verb** - verbeux (//verbose//), souvent activé par l'utilisateur quand il y a un problème, ou lorsqu'il veut les détails de l'exécution * **debug** - debug (//debug//), principalement destiné aux développeurs du module, ces messages n'étant pas normalement activés * **cmd** - exécution d'une commande (//command//), distinguer la sortie d'une commande du reste des messages peut faciliter la vie ou au moins la compréhension du processus à l'utilisateur Pour chaque type, un formatage est possible sur la sortie écran et dans le fichier de log. Pour le log, les messages et sorties écran des commandes peuvent être simplement //dumpés// tels quel, ou un préfixe peut être inséré devant chaque message, ce qui est le comportement par défaut. Bien-sûr, chacun peut être modifié indépendamment, et les préfixes peuvent être désactivés (en passant le préfixe de chaque type à une chaîne vide). Pour la sortie écran, l'affichage est plus souple puiqu'on distingue trois formats (utilisé par l'ensemble des types de messages) : * **color** afichage en couleur, et on peut modifier la couleur de chaque type de message indépendamment * **prefix** même affichage que le fichier de log * **direct** aucun formatage en sortie écran. Cela peut être pratique si le script doit être redirigé dans un tube (pipe), et une option de la ligne de commande du script peut permettre ce changement de comportement Par ailleurs, comme pour les préfixes, la couleur de chaque type peut être modifiée, soit avec une valeur prédéfinie (ensemble des couleurs ANSI) soit passé directement au module lorsqu'il effectue l'echo (cela permet des valeurs ésotériques lorsque le terminal le supporte). Plus de détails sont donnés dans la définition de la fonction **[[nlib_nio#nio_fmtlevel|nio_fmtlevel()]]**. ====Gestion d'erreur facilitée==== Un autre point important lorsqu'on écrit des scripts ayant vocation de constituer un programme complet, est la gestion des erreurs, parfois difficile, surtout lorsqu'on désire avertir l'utilisateur : il faut sauver le code d'erreur, faire l'affichage par un echo sur &2 et sortir enfin du script avec le code sauvé. **nio** fournit donc quelques fonctions permettant de simplifier ce codage répétitif et masquant le contenu //intéressant// du script. ===== Activation ===== ====Comment ?==== Pour l'instant, le script **nio.sh** est auto-suffisant. Vous pouvez donc placer ce script où bon vous semble, le //sourcer// (pas l'exécuter), et commencer à utiliser ses fonctions. Vous trouverez ce script sur subversion dans le sous-projet **nlib**. <code bash> source ou/est/situe/nio.sh || { ret=$? echo "bah oui, ndie() n'est pas disponible, c'est moins pratique :-)" >&2 exit $ret } </code> ====Et maintenant ?==== Pour bien utiliser les fonctions, et surtout les faire fonctionner selon vos attentes, il sera sûrement nécessaire de configurer le module avant d'utiliser les fonctions d'affichage. Vous pouvez commencer par définir le fichier de log à utiliser (si vous en voulez bien-sûr) : <code bash> nio_setlog -n fichier.log </code> Ensuite, définissez les types de messages pour lesquels il se passera effectivement quelquechose, et ce pour la sortie écran comme le log (mais définir les deux n'est pas obligatoire) : <code bash> # on affiche et trace les erreurs, avertissements et informations # on ajoute au log les informations détaillées et les sorties de commandes # on ajoute à l'affichage les informations de débuggage nio_setlevel -b error,warn,info -l verb,cmd -o debug </code> Puis vous pouvez modifier le format général de la sortie écran, ainsi que le formatage de chaque type de message : <code bash> nio_setformat color nio_fmtlevel -t error -c red -p '*ERROR*' nio_fmtlevel -t warn -c yellow -p '*WARNING*' nio_fmtlevel -t info -c none -p '' nio_fmtlevel -t verb -c gray -p '' nio_fmtlevel -t debug -c blue -p '*DEBUG*' nio_fmtlevel -t cmd -c darkgray -p '*CMD*' </code> A un moment donné, vous pouvez avoir besoin de modifier la configuration, mais juste dans une partie du script, ou dans un sous-script, et cela sans perdre la configuration originale; **[[nlib_nio#nio_save|nio_save()]]** et **[[nlib_nio#nio_restore|nio_restore()]]** sont vos amies ;-) : <code bash> # le script qui m'a lancé a défini une configuration de nio, # mais j'ai besoin de logger dans un fichier particulier nio_save fichier.nio # maintenant je peux faire ce que je veux avec les fonctions de paramétrage du module nio_setlog mon.fichier.specifique.log # ... # a la fin, je touche ... heu non, je restaure nio_restore fichier.nio </code> ====Configuration par défaut==== Lorsque le script est //sourcé//, la configuration définie par défaut est la suivante: * pas de fichier de log défini * tous les types de messages sont activés pour la sortie et le log * sortie écran en mode **direct** * aucune couleur définie (c'est à dire qu'après être passé en mode **color**, il faut définir les couleurs pour chaque type de message) * préfixes par défaut définis comme suit: <file> *EE* pour error *WW* pour warn *II* pour info *VV* pour verb *DD* pour debug *CC* pour cmd</file> ====Et tout ça pour quoi ?==== Maintenant que vous savez comment tout bien configurer aux petits oignons, vous pouvez utiliser les fonctions **utilisateur** : <code bash> #!/bin/bash . repertoire/ou/se/trouve/nio.sh || { ret=$? echo "impossible de sourcer 'nio.sh'." >&2 exit $ret } # lecture des paramètres while [ $# -gt 0 ]; do case $1 in -k) nio_setformat $2 || ndie "erreur de nio_setformat: $?"; shift 2;; -f) nio_setlog -n "$2" || ndie "erreur de nio_setlog: $?"; shift 2;; -b) io_both="-b $2"; shift 2;; -l) io_log="-l $2"; shift 2;; -o) io_out="-o $2"; shift 2;; *) break esac done if test -n "$io_both" || test -n "$io_log" || test -n "$io_out"; then nio_setlevel $io_both $io_log $io_out || ndie "erreur de nio_setlevel: $?" fi # place des couleurs (même si pas utilisé) nio_fmtlevel -t error -c red || ndie "erreur de nio_fmtlevel pour error: $?" nio_fmtlevel -t warn -c yellow || ndie "erreur de nio_fmtlevel pour warn: $?" nio_fmtlevel -t info -c none || ndie "erreur de nio_fmtlevel pour info: $?" nio_fmtlevel -t verb -c white || ndie "erreur de nio_fmtlevel pour verb: $?" nio_fmtlevel -t debug blue || ndie "erreur de nio_fmtlevel pour debug: $?" nio_fmtlevel -t cmd darkgray || ndie "erreur de nio_fmtlevel pour cmd: $?" ninfo tout doit fonctionner nverb avec des couleurs nwarn un avertissement nerror une erreur ndebug <<EOD Une information de debuggage mais lue depuis l'entrée standard EOD # le nverb affichera la commande exécutée pour le mode verbeux # la sortie de la commande d'affichera en gris foncé cmd='ps -ef' nverb '>>' $cmd nexec $cmd </code> ===== Les fonctions publiques ===== ====nprint()==== Génère un ou plusieurs messages en sortie et/ou en log suivant la configuration du module **nio**. ===synopsys=== <code bash> nprint -t <type> [-k] [-x <exit code>] [-e] [-n] [<msg> ..] </code> * **-t <type>** type du message, à choisir parmi //error//, //warn//, //info//, //verb//, //debug// ou //cmd// * **-k** retourne le code de sortie de la commande précédente au lieu de retourner 0 * **-x <exit code>** retourne le code de sortie spécifié au lieu de 0 * **-e** exécute les caractères spéciaux comme le ferait la commande **echo** * **-n** n'ajoute pas de caractère 'nouvelle ligne' à la fin du message * **<msg> ..** liste de messages à générer, en utilisant l'entrée standard si aucun message n'est spécifié ===valeurs de retour=== * **0** - ok * **200** - mauvais appel, vérifier les paramètres passés ===utilisation=== Deux façon de l'utiliser, avec un ou plusieurs messages en paramètre : <code bash> nprint -t info "le message" ./commande_qui_retourne_127 || nprint -t warn -k "ça a foiré !" " Pas si grave que ça ;-)" echo "la commande a retourné $?" # affichera 127 </code> ou sans paramètre, mais en utilisant l'entrée standard <code bash> get_translated_message "my taylor is rich :-)" | nprint -t verb nprint -t debug <<EOM Ici donc les informations de débuggage, car c'est important d'activer des informations complémentaires lorsqu'on est en train de programmer un truc :p. EOM </code> ====nerror() / nwarn() / ninfo() / nverb() / ndebug==== Version simplifiée de **[[nlib_nio#nprint|nprint()]]** avec le paramètre **-t** implicite. ====ntitle()==== Modifie le titre de la fenêtre d'émulateur de terminal. ===synopsys=== <code bash> ntitle <string> </code> ===valeurs de retour=== Toujours 0. ===utilisation=== Indiquer le titre à la fonction : <code bash> ntitle "Le titre de mon terminal" </code> ====nexec()==== Exécute la commande spécifiée en utilisant **[[nlib_nio#nprint|nprint()]]** avec le type **cmd** pour la sortie. ===synopsys=== <code bash> nexec <command> [<arg> ..] </code> ===valeurs de retour=== Retourne le code de la commande. ===utilisation=== <code bash> nexec ps -ef || ndie "ps ne marche pas ? problème de droits ? voyez votre admin" </code> ====ndie()==== Met fin au script courant avec la valeur de retour de la dernière commande, ou celle spécifiée, en affichant (et loggant) un message si demandé. En arrière plan, **ndie()** appelle **[[nlib_nio#nerror_nwarn_ninfo_nverb_ndebug|nerror()]]** pour générer le message. ===synopsys=== <code bash> ndie [-x <exit code>] [ - | <msg> .. ] </code> * **-x <exit code>** indique le code de sortie à retourner au lieu de celui de la dernière commande * **-** demande la lecture du message depuis l'entrée standard - contrairement aux fonctions d'affichage de messages, ces derniers ne sont pas obligatoires pour cette fonction, il faut donc indiquer que l'on désire lire depuis l'entrée standard en plaçant cet argument * **<msg> ..** génère la liste de messages pour **nerror()** ===valeurs de retour=== * **200** mauvais appel, vérifier les paramètres * la valeur de retour de la dernière commande, ou celle specifiée avec **-x** ===utilisation=== <code bash> ./commande_qui_echoue || ndie ./et_pof 2>/dev/null || ndie "j'affiche ce message pour dire que c'est terminé" ./pas_glop || ndie -x 1 <<EOM retour avec le code de sortie 1, quelquesoit la valeur retournée par pas_glop EOM </code> ====nrequire()==== Vérifie si le fichier existe, et le //source// si demandé. Un message d'erreur est affiché/loggué si demandé (utilise **[[nlib_nio#ndie|ndie()]]**). ===synopsys=== <code bash> nrequire [-s] <filename> [<msg> ..] </code> * **-s** demande à ce que le fichier soit //sourcé// s'il existe * **<filename>** le fichier à vérifier * **<msg> ..** liste de messages à afficher/logguer en cas d'erreur ===valeurs de retour=== * **0** - ok * **1** - le fichier n'existe pas * **200** - mauvais appel, vérifier les paramètres ===utilisation=== <code bash> nrequire ./ca_existe # exit si n'existe pas nrequire -s ./ca_existe # cette fois, on le source nrequire ./ca_existe_aussi "le fichier n'existe pas" </code> ====nio_setlog()==== Modifie le nom de fichier de log, ou désactive le log (nom de fichier vide) ===synopsys=== <code bash> nio_setlog [-n] [<logfile>] </code> * **-n** crée un nouveau fichier ou remet l'existant à vide (sinon les nouvelles lignes sont ajoutées à la fin du fichier) * **<logfile>** le nom du fichier de log ===valeurs de retour=== * **0** - ok * **1** - erreur lors de la création du fichier vide (permissions ?) ===utilisation=== <code bash> nio_setlog -n ../mon/fichier.log || ndie "impossible de créer ou écraser le fichier de log" nio_setlog ../autre/fichier.log || ndie "bah décidemment !" nio_setlog ../mon/fichier.log # cette ligne remet le fichier de log original sans écraser son contenu </code> ====nio_getlevels()==== Cette fonction n'a que peu d'intérêt pour le moment, mais elle existe :-). Elle affiche sur la sortie standard (sûrement redirigée) la liste des types de messages supportés, séparés par des espace. Aujourd'hui, cette fonction affiche <file>error warn info verb debug cmd</file> Il est prévu dans le futur que l'utilisateur puisse ajouter ses propres types de messages; cette fonction permettra de tous les lister. ===synopsys=== <code bash> nio_getlevels </code> ===valeurs de retour=== Toujours 0. ===utilisation=== <code bash> for type in `nio_getlevels`; do nprint -t $type "affiche le type $type" done </code> ====nio_setlevel==== Définit les types de messages pris en compte pour une sortie écran et/ou une trace en log. Il est possible de définir séparément les types pour chacune des deux actions, de définir un ensemble commun, ou une combinaison des deux. Les masques sont des listes de types séparés par une virgule, et l'ensemble des types supportés est disponible via la fonction **[[nlib_nio#nio_getlevels|nio_getlevels()]]**. ===synopsys=== <code bash> nio_setlevel [-b <both masks>] [-l <log mask>] [-o <out mask>] </code> * **-b <both masks>** masque des types pour les deux actions (output et log) * **-l <log mask>** masque des types pour le log * **-o <out mask>** masque des types pour la sortie écran (stdout) Lorsque **-b** est spécifié, les types indiqués sont concaténés aux types indiqués par **-l** ou **-o**. ===valeurs de retour=== * **0** - ok * **200** - mauvais appel, vérifier les paramètres * **201** - au moins un type dans les masques n'est pas valide ===utilisation=== <code bash> # pas de distinction entre output et log nio_setlevel -b error,warn,info,cmd # la sortie contient les erreurs, avertissements, informations générales # et informations de debuggage. # le log contient les mêmes types que le log, sans le debug, mais avec # la sortie des commandes en plus nio_setlevel -b error,warn,info -o debug -l cmd # cet appel est identique : nio_setlevel -o error,warn,info,debug -l error,warn,info,cmd </code> ====nio_setformat()==== Indique le type de sortie écran. Le log utilise toujours le préfixe((On peut vider les chaînes de préfixes pour avoir un log //brut//.)). ===synopsys=== <code bash> nio_setformat direct|color|prefix </code> * **direct** pas de formatage, les messages sont affichés tels quels * **color** utilise les couleurs pour la sortie (les couleurs sont modifiées avec le paramètre **-c** de la fonction **[[nlib_nio#nio_fmtlevel|nio_fmtlevel()]]**) * **prefix** utilise le même préfixe que pour le log (log et sortie écran identiques) ===valeurs de retour=== * **0** - ok * **200** - mauvais appel, vérifier que vous avez bien spécifié **direct**, **color** ou **prefix** en paramètre ===utilisation=== Voir la [[nlib_nio#et_maintenant|présentation du module]]. ====nio_fmtlevel()==== Modifie le formatage d'un type de message. ===synopsys=== <code bash> nio_fmtlevel -t <type> [-c <color>] [-p <prefix>] </code> * **-t <type>** type de message à modifier, parmi ceux [[nlib_nio#nio_getlevels|disponibles]] * **-c <color>** couleur à utiliser pour ce type de message (ce paramètre n'a d'effet que si le [[nlib_nio#nio_setformat|format général]] est **color**), vous pouvez utiliser les raccourcis prédéfinis ci-après, ou tout code ANSI valide (par exemple //1;34// qui est équivalent au raccourci //blue//) : <file>black darkgray darkred red darkgreen green brown yellow darkblue blue purple pink darkcyan cyan gray white none</file> (la valeur //none// désactive la couleur) * **-p <prefix>** préfixe à utiliser pour le log (et la sortie écran si le format général est **prefix**), vous pouvez désactiver le préfixe pour le log et la sortie écran en indiquant une chaîne vide ===valeurs de retour=== * **0** - ok * **200** - mauvais appel, vérifier les paramètres ===utilisation=== Voir la [[nlib_nio#et_maintenant|présentation du module]]. ====nio_save()==== Sauve dans le fichier indiqué la configuration du module telle que définie par les appels à **[[nlib_nio#nio_setlog|nio_setlog()]]**, **[[nlib_nio#nio_setlevel|nio_setlevel()]]**, **[[nlib_nio#nio_setformat|nio_setformat()]]** ou **[[nlib_nio#nio_fmtlevel|nio_fmtlevel()]]**. ===synopsys=== <code bash> nio_save <filename> </code> * **<filename>** le nom du fichier dans lequel sauver les informations de configuration ===valeurs de retour=== Cette fonction utilise le programme **cat**, la valeur retournée est celle de ce programme. ===utilisation=== Voir la [[nlib_nio#et_maintenant|présentation du module]]. ====nio_restore()==== Restaure une configuration du module précédemment sauvegardée avec **[[nlib_nio#nio_save|nio_save()]]**. ===synopsys=== <code bash> nio_restore <filename> [<error message> ..] </code> * **<filename>** le même nom de fichier spécifié à **nio_save()** * **<error message> ..** liste de messages à générer en cas d'erreur ===valeurs de retour=== Cette fonction utilise **[[nlib_nio#nrequire|nrequire()]]**, la valeur de retour est celle de cette fonction. ===utilisation=== Voir la [[nlib_nio#et_maintenant|présentation du module]].