La petite technique shell du vendredi. Pour lire un fichier de configuration du style INI depuis un script shell, on peut utiliser le petit script sed suivant
1 {
x
s/^/default/
x
}
/^#/n
/^\[/ {
s/\[\(.*\)\]/\1/
x
b
}
/=/ {
s/^[[:space:]]*//
s/[[:space:]]*=[[:space:]]*/|/
G
s/\(.*\)\n\(.*\)/\2|\1/
p
}
Il transforme
# last modified 1 April 2001 by John Doe
[owner]
name=John Doe
organization=Acme Widgets Inc.
[database]
# use IP address in case network name resolution is not working
server=192.0.2.62
port=143
file=payroll.dat
en
owner|name|John Doe
owner|organization|Acme Widgets Inc.
database|server|192.0.2.62
database|port|143
database|file|payroll.dat
et ce deuxième format est facile à lire avec awk ou read par exemple.
Avec le shell l'approche classique consiste à sourcer un script contenant des définitions de variables, ce qui peut impliquer des trous de sécurité et n'offre pas beaucoup de possibilités de structuration.
Je le raconte (en pareil et en anglais) sur mon blog.
# sed, c'est dien !
Posté par Ramón Perez (site web personnel) . Évalué à 10.
# Perl r0x
Posté par tfeserver tfe (site web personnel) . Évalué à 10.
Petite version rapide en Perl:
perl -ne '/^\s*\[(.*?)]/ and $c=$1; /^\s*([^=]+)=(.*)/ and print "$c|$1|$2\n"; ' < fichier.ini
[^] # Re: Perl r0x
Posté par flan (site web personnel) . Évalué à 3. Dernière modification le 06 juin 2015 à 10:09.
Ça me donne surtout envie d'utiliser un autre langage :(
[^] # Re: Perl r0x
Posté par Sytoka Modon (site web personnel) . Évalué à 7.
C'est franchement difficile d'être plus clair pourtant ! On a juste deux commandes, une qui pose le contexte, une qui fait la sortie. C'est juste une petite merveille.
Il faut savoir être ouvert sur les autres tribus et reconnaître à chacun ses mérites ;-)
[^] # Re: Perl r0x
Posté par flan (site web personnel) . Évalué à 2.
Honnêtement, je ne comprends rien à ce que ça fait, et pourtant j'ai fait un (tout petit) peu de Perl il y a quelques années. Là, je ne saurais même pas dire ce que ça donne en pratique.
A contrario, j'ai déjà réussi à patcher du Ruby sans jamais en avoir fait.
[^] # Re: Perl r0x
Posté par Sytoka Modon (site web personnel) . Évalué à 6.
Attention, c'est du one-liner, l'objectif est principalement ici d'écrire du code jetable et celui-ci est particulièrement lisible malgré ce que tu dis. Ceci dis, si tu n'y comprends rien, je pense qu'une petite plongée dans Perl ne peut alors que faire du bien histoire d'ouvrir de nouveau paradigme ;-) Bref, c'est une bête machine à état basée sur deux expressions rationnelles assez simples. Il y a pleins de one-liner incompréhensibles (c'est aussi un jeu) mais honnêtement, pas celle-là ;-)
[^] # Re: Perl r0x
Posté par polux14 . Évalué à 2.
J'ai trop souvent l'impression que Perl est jugé sur ses variables explicites et l'intégration forte des expressions régulières (qui peuvent rendre le code peu lisible, certes).
Mais pour faire une analogie douteuse, c'est un peu comme dire que le chinois c'est incompréhensible car ce n'est pas un alphabet latin.
Petit patch:
perl -ne '/^\s*\[(.*?)]/ and $c=$1; /^\s*([^=#]+)=(.*)/ and print "$c|$1|$2\n"; ' < fichier.ini
[^] # Re: Perl r0x
Posté par anaseto . Évalué à 8.
Le truc amusant c'est que cette intégration rend, paradoxalement, les expressions régulières potentiellement bien plus lisibles : moins d'échappements à faire, possibilité de les écrire sur plusieurs lignes avec des commentaires et support possible de la part de l'éditeur de texte pour la coloration (vu que ce n'est pas juste des chaîne de caractères ordinaires), auxquels on peut ajouter le fait d'avoir certains messages d'erreurs dans des regex à la compilation et non à l'exécution.
Je pense que Perl est plutôt généralement jugé sur la possibilité d'écrire des one-liner ou petits scripts très compacts, car c'est souvent la partie la plus visible pour celui qui ne connaît pas Perl, celle qu'il a le plus de chances de rencontrer en tombant sur un forum au hasard, et, malheureusement, c'est probablement une des disciplines qui montrent les parties les moins évidentes et implicites du langage. À côté, le code Perl d'un développement un peu plus gros est beaucoup plus accessible.
# Vraiment en shell
Posté par ymorin . Évalué à 4.
Ou alors, en restant vraiment en shell (bash 4.0+):
Hop,
Moi.
[^] # Re: Vraiment en shell
Posté par Sytoka Modon (site web personnel) . Évalué à 5.
Si tu restes en pure bash, tu ne mets pas de $( ) … La première qu'on voit dans ton script sont les sous commandes sed ! Bref, la monoligne Perl est vraiment plus esthétique et rapide. Si tu veux des variables à la fin, à peine modifié, tu fait un eval de son résultat.
[^] # Re: Vraiment en shell
Posté par Michaël (site web personnel) . Évalué à 2.
Ce n'est pas du bash pur car tu appelles une ou deux fois sed par ligne lue, et cela ne fait pas du tout la même chose car tu ne produis pas de donnée tabulaire. Remarque, je ne programme pas en bash car c'est tout plein de bugs — dès que le job control devient compliqué, cela fait des segfaults.
# pure bash et un peu long
Posté par bunam . Évalué à -1.
j'ai utilisé
exemple :
[^] # Re: pure bash et un peu long
Posté par Sébastien Koechlin . Évalué à 10.
Sérieusement, quasiment 300 lignes pour lire un fichier ini, traiter les quotes à la main, tripoter IFS et shopt; il n'y a vraiment pas de quoi être fier.
C'est un bel exemple de code complètement non maintenable. En prime chacun y va de sa copie sans jamais faire la moindre mise à jour histoire de variés les bugs d'un code à l'autre.
[^] # Re: pure bash et un peu long
Posté par kaliko (site web personnel) . Évalué à 7. Dernière modification le 06 juin 2015 à 14:07.
Quand un script shell dépasse les 100 lignes il est temps de basculer sur un vrai^Wautre langage.
Par exemple en python:
Pourquoi réécrire du code pour traiter un format standard (ie INI files), c'est tout l'intérêt de passer par un standard, hériter du travail fait par d'autre sur le sujet.
Cependant l'exercice reste intéressant pour la beauté du geste et l'exploration des possibilités du shell.
Dans le cadre de scripting système dans un environnement pro ça me semble en effet une mauvaise idée de construire de trop gros script en pur shell.
[^] # Re: pure bash et un peu long
Posté par Christophe B. (site web personnel) . Évalué à 1.
@!#$ devancé de plus d'une heure
je salivais à l'avance d'étaler ma science python …
me reste plus que la mauvaise foi unixienne de base :
ouiiii maiiiiiis python va consommer 15 fois plus de RAM que le shell …
tu as raison mais le shell reste quand même la meilleure glue qui soit sous unix
de plus sur certain OS difficile à écarter, comme AIX, python n'est installé en standard, même si c'est faisable facilement
Sinon le couple shell + python c'est quand même le top pour les scripts complexes comme les "exits" de CFT par exemple.
[^] # Re: pure bash et un peu long
Posté par Sytoka Modon (site web personnel) . Évalué à 2.
Tu veux juste dire que Python est un langage déclaratif qui a un certain de module bien fait ;-)
use Config::Tiny;
my $Config = Config::Tiny->read('/etc/myinifile.cfg');
[^] # Re: pure bash et un peu long
Posté par Michaël (site web personnel) . Évalué à 5.
Contrairement à plein de croyances, ce n'est pas si difficile d'écrire des programmes complexes, maintenables et relativement gros avec le shell. La clef c'est de ne pas utiliser le shell n'importe comment. En gros il faut éviter le plus possible de maintenir des données complexes dans le shell lui-même, le shell servant juste à lancer des programmes — plus spécifiquement, des filtres — qui vont effectuer les traitements. En général on part de fonctions “prototypes” et de “mockings” pour écrire très rapidement un prototype. Ensuite on étend le prototype et on peut remplacer les traitements trop complexes par des programmes autonomes. Évidemment, il s'agit de faire du bon gros traitement de données pas du tout interactif, pour les programmes interactifs, cette approche ne va pas du tout!
[^] # Re: pure bash et un peu long
Posté par bunam . Évalué à 1.
Je pense être le seul à répondre au problème : shell et config type ini ;p
[^] # Re: pure bash et un peu long
Posté par barmic . Évalué à 3.
On peut faire plus simple :
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: pure bash et un peu long
Posté par Benoît Sibaud (site web personnel) . Évalué à 3.
Petite correction d'ortho : property pas propertie. Il faudra aussi définir la fonction die.
[^] # Re: pure bash et un peu long
Posté par barmic . Évalué à 3.
Voici la fonction die telle que je m'en sert généralement :
Elle n'est AMHA pas nécessaire à comprendre la logique de la méthode.
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: pure bash et un peu long
Posté par Benoît Sibaud (site web personnel) . Évalué à 3.
Pour éviter ça :
je propose plutôt
[^] # Re: pure bash et un peu long
Posté par Michaël (site web personnel) . Évalué à 2.
C'est probablement does not exist ou doesn't exist. Mais au passage exist ça fait un peu vocabulaire mathématique et on utilise souvent plutôt no such … ou … not found — par exemple chez moi:
[^] # Re: pure bash et un peu long
Posté par Michaël (site web personnel) . Évalué à 2.
Mais ça ne fait pas du tout la même chose que le script sed puisque cela définit tout un tas de variables avec les valeurs assignées, du coup à moins de faire de l'introspection plutôt hasardeuse, tu ne peux pas itérer sur les valeurs définies mais seulement lire les valeurs que tu attends.
Avec le script sed on peut transformer un fichier INI comme la config de git en donnée tabulaire, du type
ce qui permet de sélectionner avec awk toutes les url de remotes par exemple.
[^] # Re: pure bash et un peu long
Posté par barmic . Évalué à 3.
Ton format csv est une plaie à utiliser en shell. On peut facilement modifier mon script pour créer des tableaux associatifs dont le nom correspond à la section et la clef le nom de la variable.
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: pure bash et un peu long
Posté par Michaël (site web personnel) . Évalué à 2. Dernière modification le 09 juin 2015 à 09:00.
On est régulièrement en désaccord là-dessus. Pour moi les données tabulaires sont à la base de la programmation en shell et je n'écris quasiment que des filtres qui lisent et écrivent des données tabulaires – et font parfois quelques traitement aussi! – bien-sûr cela demande de ne pas écrire de caractères NUL, de CR ou PIPE dans les champs, mais dans mon cas ce n'est pas une limitation.
Je suis donc très content avec les données tabulaires. Quels sont les problèmes qu'elles te posent?
[^] # Re: pure bash et un peu long
Posté par barmic . Évalué à 3.
Ça se manipule bien avec des sed/grep/awk/perl, mais en shell c'est une infamie.
Par contre de manière générale, le fait de s'en servir avec des filtres ça sert quand tu cherche à traiter le contenu du fichier INI, quand tu veut t'en servir comme d'une configuration, l'utilisation sous forme tabulaire n'est pas pratique (tu dois de toute manière déserialiser ton fichier).
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: pure bash et un peu long
Posté par Michaël (site web personnel) . Évalué à 2. Dernière modification le 09 juin 2015 à 10:24.
Ma règle d'or de la programmation shell est de traiter aussi peu de données que possible avec le shell que je considère plutôt comme un outil de description des workflows qui transfère des données d'/un processus à l'autre, si possible sans regarder ce qu'il y a dedans.
Ça dépend un peu des cas d'utilisation: s'il s'agit de lire une batterie de paramètres, je suis complètement d'accord avec toi, cependant si on a une collection de valeurs a priori inconnue (du style git qui a des paramètres pour chaque branche, mais ne connaît pas a priori le nom des branches), alors une donnée tabulaire peut-être pertinente.
On peut aussi traduire la donnée tabulaire en fichier contenant des affectations puis sourcer ce fichier, au lieu de faire ça “ligne à ligne” ce qui est forcément très bavard (code) et très lent.
[^] # Re: pure bash et un peu long
Posté par barmic . Évalué à 3.
C'est toi que ça regarde.
Pour utiliser différents outils de workflow (ou affilié) le shell est assez mauvais pour ça (utiliser plus d'entrée et de sortie que ceux prévu en standard n'est pas très pratique, complexité de créer des routes avec plus d'une entrée et plus d'une sortie, aucun mécanisme de monitoring de ce que se passe, difficulté de debugage (beaucoup de monde écris cmd1|cmd2|cmd3 sans s'intéresser à gérer les erreurs de la commande cmd2, etc).
Bref ce n'est AMHA pas parce qu'il fait des pipes que ça en fait un outil de description de workflow, ou du moins il a à peu près autant de défaut pour décrire des workflow que pour gérer des données.
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: pure bash et un peu long
Posté par Michaël (site web personnel) . Évalué à 3.
Heu, je ne comprends pas trop le sens de cette discussion? J'explique pourquoi je n'ai pas de problème à traiter les données tabulaires avec le shell c'est tout simplement parceque je ne le fais pas – et ce, sciemment. C'est grave d'échanger des points de vue et des expériences?
Effectivement, pour les tâches complexes, je trouve le shell excellent pour écrire des prototypes – plutôt fragiles et lents, mais rapides à écrire.
[^] # Re: pure bash et un peu long
Posté par Michaël (site web personnel) . Évalué à 2.
Qu'est-ce que tu utilises dont tu es content? J'ai commencé à implémenter une bibliothèque en OCaml pour faire cela et j'aimerais bien regarder l'API d'autres solutions pour m'en inspirer.
# En bash, à la rache
Posté par kna . Évalué à -1.
[^] # Re: En bash, à la rache
Posté par Sytoka Modon (site web personnel) . Évalué à 4.
Enfin, bash + grep étendus + tr + sed…
[^] # Re: En bash, à la rache
Posté par Michaël (site web personnel) . Évalué à 3.
Quitte à lancer une instance de sed autant la laisser faire tout le travail, non?
# En python, c'est quand même plus simple
Posté par Dabowl_75 . Évalué à 2.
Le fichier de config .ini :
Le code pour parser le fichier et peupler des variables.
[^] # Re: En python, c'est quand même plus simple
Posté par Sytoka Modon (site web personnel) . Évalué à 0.
Ah la vache, c'est caca boudin ! Deux try/except en aussi peu de ligne, aucune variable déclarée… C'est quoi ce langage de daube ;-)
[^] # Re: En python, c'est quand même plus simple
Posté par Dabowl_75 . Évalué à 2.
Premier try/catch :
il faut bien tester le cas où le fichier n'est pas accessible pour plein de raisons.
Second try/catch :
Il faut bien s'assurer que les variables dont le script a besoin pour fonctionner, sont bien présentes dans le fichier de config ini, et de surcroire dans la bonne section (ce qui valide la présence des sections).
Au contraire, je trouve ça très simple et relativement concis puisqu'on vérifie quand même pas mal de choses en très peu de lignes.
Il suffit de comparer avec les codes shell précédents….
Alors ok je m'appuie sur une api, donc une partie du boulot et déjà fait, mais je ne vois pas l'intérêt de réinventer la roue.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.