Je souhaite fournir un fichier de configuration structuré qui soit aussi facile que possible à modifier pour un utilisateur non technique (malheureusement, il doit s'agir d'un fichier) et j'ai donc voulu utiliser YAML. Cependant, je ne trouve aucun moyen d'analyser cela à partir d'un script shell Unix.
193
yq
pour lire / écrire des fichiers yaml dans le shell. La page du projet est ici: mikefarah.github.io/yq Vous pouvez installer l'outil avecbrew
,apt
ou télécharger le binaire. La lecture d'une valeur est aussi simple queyq r some.yaml key.value
Réponses:
Mon cas d'utilisation peut ou non être tout à fait le même que ce que ce message original demandait, mais il est certainement similaire.
J'ai besoin de tirer quelques YAML en tant que variables bash. Le YAML n'aura jamais plus d'un niveau de profondeur.
YAML ressemble à ceci:
Sortie comme un dis:
J'ai réalisé le résultat avec cette ligne:
s/:[^:\/\/]/="/g
le trouve:
et le remplace par="
, tout en ignorant://
(pour les URL)s/$/"/g
ajoute"
à la fin de chaque lignes/ *=/=/g
supprime tous les espaces avant=
la source
{KEY: 'value', ...}
; et éventuellement d'autres. Plus important encore, si vous avez l'intention d'évaluer le résultat en tant que code shell, ce serait très peu sûr.Voici un analyseur bash uniquement qui exploite sed et awk pour analyser des fichiers yaml simples:
Il comprend des fichiers tels que:
Qui, une fois analysé en utilisant:
affichera:
il comprend également les fichiers yaml, générés par ruby qui peuvent inclure des symboles ruby, comme:
et affichera le même que dans l'exemple précédent.
l'utilisation typique dans un script est:
parse_yaml accepte un argument de préfixe afin que les paramètres importés aient tous un préfixe commun (ce qui réduira le risque de collisions d'espace de noms).
donne:
Notez que les paramètres précédents d'un fichier peuvent être référencés par des paramètres ultérieurs:
Une autre utilisation intéressante consiste à analyser d'abord un fichier par défaut, puis les paramètres utilisateur, ce qui fonctionne car ces derniers remplacent les premiers:
la source
-
notation yaml en tableaux bash natifs!global__debug
au lieu deglobal_debug
.J'ai écrit
shyaml
en python pour les besoins des requêtes YAML à partir de la ligne de commande du shell.Aperçu:
Exemple de fichier YAML (avec des fonctionnalités complexes):
Requête de base:
Requête en boucle plus complexe sur des valeurs complexes:
Quelques points clés:
\0
la sortie rembourrée est disponible pour la manipulation d'entrée multiligne solide.subvalue.maintainer
est une clé valide).subvalue.things.-1
est le dernier élément de lasubvalue.things
séquence.)Plus d'exemples et de documentation sont disponibles sur la page shyaml github ou la page shyaml PyPI .
la source
cat docker-compose.yml | shyaml get-value api.environment | grep -v null | awk -F': ' '{print $2 > ("envdir/" $1)}'
shyaml
est ridiculement lent( https://github.com/mikefarah/yq#readme )
A titre d'exemple (volé directement dans la documentation ), étant donné un fichier sample.yaml de:
puis
sortira
la source
Il est possible de passer un petit script à certains interprètes, comme Python. Un moyen simple de le faire en utilisant Ruby et sa bibliothèque YAML est le suivant:
, où
data
est un hachage (ou un tableau) avec les valeurs de yaml.En prime, il analysera très bien les avant- propos de Jekyll .
la source
RUBY_SCRIPT
variable est un script ruby qui peut être écrit dans un fichier à la place (exécuté avecruby -ryaml <rubyscript_filename>
). Il contient la logique pour transformer le texte d'entrée en un texte de sortie, stockant en interne le contenu dans ladata
variable. L'écho produit un texte yaml, mais vous pouvez l'utilisercat <yaml_filename>
pour diriger le contenu d'un fichier à la place.stdout
variable soit introduite dans la variable, vous n'avez pas à vous fier fichiers temporaires! utiliserx=$(...)
ou mêmeread a b c < <(...)
). Il s'agit donc d'une solution valide lorsque vous savez exactement ce que vous voulez récupérer dans le fichier YAML et que vous savez comment écrire les lignes ruby pour accéder à ces données. Même si c'est approximatif, c'est une preuve complète de concept de l'idée IMHO. Il est vrai néanmoins que cela ne vous fournit pas une abstraction complète.Étant donné que Python3 et PyYAML sont des dépendances assez faciles à rencontrer de nos jours, les éléments suivants peuvent aider:
la source
yaml.safe_load
car il est plus sûr. pyyaml.org/wiki/PyYAMLDocumentationvoici une version étendue de la réponse de Stefan Farestam:
Cette version prend en charge la
-
notation et la notation courte pour les dictionnaires et les listes. L'entrée suivante:produit cette sortie:
comme vous pouvez le voir, les
-
éléments sont automatiquement numérotés afin d'obtenir des noms de variables différents pour chaque élément. Ilbash
n'y a pas de tableaux multidimensionnels, c'est donc une façon de contourner. Plusieurs niveaux sont pris en charge. Pour contourner le problème avec les espaces blancs de fin mentionnés par @briceburg, vous devez placer les valeurs entre guillemets simples ou doubles. Cependant, il existe encore certaines limitations: l'expansion des dictionnaires et des listes peut produire des résultats erronés lorsque les valeurs contiennent des virgules. De plus, les structures plus complexes comme les valeurs couvrant plusieurs lignes (comme les clés ssh) ne sont pas (encore) prises en charge.Quelques mots sur le code: La première
sed
commande étend la forme abrégée des dictionnaires{ key: value, ...}
en standard et les convertit en un style yaml plus simple. Le deuxièmesed
appel fait de même pour la notation courte des listes et se convertit[ entry, ... ]
en une liste détaillée avec la-
notation. Le troisièmesed
appel est celui d'origine qui traitait les dictionnaires normaux, maintenant avec l'ajout pour gérer les listes avec-
et indentations. Laawk
partie introduit un index pour chaque niveau d'indentation et l'augmente lorsque le nom de la variable est vide (c'est-à-dire lors du traitement d'une liste). La valeur actuelle des compteurs est utilisée à la place du vname vide. En remontant d'un niveau, les compteurs sont remis à zéro.Edit: j'ai créé un référentiel github pour cela.
la source
Difficile à dire car cela dépend de ce que vous voulez que l'analyseur extrait de votre document YAML. Pour les cas simples, vous pourriez être en mesure d'utiliser
grep
,cut
,awk
etc. Pour l' analyse plus complexe , vous devez utiliser une bibliothèque entière analyse tels que Python PyYAML ou YAML :: Perl .la source
Je viens d'écrire un analyseur que j'ai appelé Yay! ( Yaml n'est pas Yamlesque! ) Qui analyse Yamlesque , un petit sous-ensemble de YAML. Donc, si vous recherchez un analyseur YAML 100% conforme pour Bash, ce n'est pas ça. Cependant, pour citer l'OP, si vous voulez un fichier de configuration structuré qui soit aussi facile que possible pour un utilisateur non technique à éditer qui soit de type YAML, cela peut être intéressant.
Il est inséré par la réponse précédente mais écrit des tableaux associatifs ( oui, il nécessite Bash 4.x ) au lieu de variables de base. Il le fait d'une manière qui permet aux données d'être analysées sans connaissance préalable des clés afin que le code basé sur les données puisse être écrit.
En plus des éléments du tableau clé / valeur, chaque tableau a un
keys
tableau contenant une liste de noms de clés, unchildren
tableau contenant les noms des tableaux enfants et uneparent
clé qui fait référence à son parent.Voici un exemple de Yamlesque:
Voici un exemple montrant comment l'utiliser:
qui sort:
Et voici l'analyseur:
Il y a une documentation dans le fichier source lié et ci-dessous est une brève explication de ce que fait le code.
La
yay_parse
fonction localise d'abord leinput
fichier ou se termine avec un statut de sortie de 1. Ensuite, elle détermine l'ensemble de donnéesprefix
, soit explicitement spécifié soit dérivé du nom de fichier.Il écrit des
bash
commandes valides dans sa sortie standard qui, si elles sont exécutées, définissent des tableaux représentant le contenu du fichier de données d'entrée. Le premier de ceux-ci définit le tableau de niveau supérieur:Notez que les déclarations de tableau sont associatives (
-A
), ce qui est une fonctionnalité de Bash version 4. Les déclarations sont également globales (-g
) afin qu'elles puissent être exécutées dans une fonction mais être disponibles pour la portée globale comme l'yay
aide:Les données d'entrée sont initialement traitées avec
sed
. Il supprime les lignes qui ne correspondent pas à la spécification de format Yamlesque avant de délimiter les champs Yamlesque valides avec un caractère séparateur de fichier ASCII et de supprimer les guillemets doubles entourant le champ de valeur.Les deux expressions sont similaires; ils diffèrent uniquement parce que le premier choisit les valeurs cotées alors que le second choisit les valeurs non cotées.
Le séparateur de fichiers (28 / hex 12 / octal 034) est utilisé car, en tant que caractère non imprimable, il est peu probable qu'il se trouve dans les données d'entrée.
Le résultat est acheminé dans
awk
lequel traite son entrée une ligne à la fois. Il utilise le caractère FS pour affecter chaque champ à une variable:Toutes les lignes ont un retrait (éventuellement zéro) et une clé mais elles n'ont pas toutes une valeur. Il calcule un niveau d'indentation pour la ligne divisant la longueur du premier champ, qui contient l'espace blanc de début, par deux. Les éléments de niveau supérieur sans aucun retrait sont au niveau de retrait zéro.
Ensuite, il détermine ce qu'il
prefix
faut utiliser pour l'élément actuel. C'est ce qui est ajouté à un nom de clé pour créer un nom de tableau. Il y a unroot_prefix
pour le tableau de niveau supérieur qui est défini comme le nom de l'ensemble de données et un trait de soulignement:Le
parent_key
est la clé au niveau de retrait au-dessus du niveau de retrait de la ligne actuelle et représente la collection dont la ligne actuelle fait partie. Les paires clé / valeur de la collection seront stockées dans un tableau avec son nom défini comme la concaténation deprefix
etparent_key
.Pour le niveau supérieur (retrait de niveau zéro), le préfixe de l'ensemble de données est utilisé comme clé parente, il n'a donc pas de préfixe (il est défini sur
""
). Tous les autres tableaux sont précédés du préfixe racine.Ensuite, la clé actuelle est insérée dans un tableau (awk-internal) contenant les clés. Ce tableau persiste pendant toute la session awk et contient donc des clés insérées par les lignes précédentes. La clé est insérée dans le tableau en utilisant son retrait comme index du tableau.
Étant donné que ce tableau contient des clés des lignes précédentes, toutes les clés avec un niveau d'indentation supérieur au niveau d'indentation de la ligne actuelle sont supprimées:
Cela laisse le tableau de clés contenant le porte-clés de la racine au niveau d'indentation 0 à la ligne courante. Il supprime les clés obsolètes qui restent lorsque la ligne précédente était plus profonde que la ligne actuelle.
La dernière section produit les
bash
commandes: une ligne d'entrée sans valeur démarre un nouveau niveau d'indentation (une collection en langage YAML) et une ligne d'entrée avec une valeur ajoute une clé à la collection actuelle.Le nom de la collection est la concaténation des lignes actuelles
prefix
etparent_key
.Lorsqu'une clé a une valeur, une clé avec cette valeur est affectée à la collection actuelle comme ceci:
La première instruction génère la commande pour affecter la valeur à un élément de tableau associatif nommé d'après la clé et la seconde renvoie la commande pour ajouter la clé à la
keys
liste délimitée par des espaces de la collection :Lorsqu'une clé n'a pas de valeur, une nouvelle collection est démarrée comme ceci:
La première instruction renvoie la commande pour ajouter la nouvelle collection à la
children
liste délimitée par des espaces de la collection actuelle et la seconde renvoie la commande pour déclarer un nouveau tableau associatif pour la nouvelle collection:Toute la sortie de
yay_parse
peut être analysée en tant que commandes bash par les commandes basheval
ousource
intégrées.la source
examples
etusr/lib
, Ceux-ci sont liés dans ma réponse à la question. S'il y a un intérêt, je pourrais le diviser en son propre repo.la source
Une autre option consiste à convertir le YAML en JSON, puis à utiliser jq pour interagir avec la représentation JSON, soit pour en extraire des informations, soit pour la modifier.
J'ai écrit un script bash simple qui contient cette colle - voir le projet Y2J sur GitHub
la source
Si vous avez besoin d'une valeur unique, vous pouvez utiliser un outil qui convertit votre document YAML en JSON et alimente
jq
, par exempleyq
.Contenu de sample.yaml:
Exemple:
la source
Je sais que c'est très précis, mais je pense que ma réponse pourrait être utile pour certains utilisateurs.
Si vous avez
node
etnpm
installé sur votre machine, vous pouvez utiliserjs-yaml
.Première installation:
puis dans votre script bash
Aussi, si vous utilisez,
jq
vous pouvez faire quelque chose comme çaParce que
js-yaml
convertit un fichier yaml en un littéral de chaîne json. Vous pouvez ensuite utiliser la chaîne avec n'importe quel analyseur json de votre système unix.la source
Si vous avez python 2 et PyYAML, vous pouvez utiliser cet analyseur que j'ai écrit appelé parse_yaml.py . Certaines des choses les plus intéressantes qu'il fait est de vous permettre de choisir un préfixe (au cas où vous auriez plus d'un fichier avec des variables similaires) et de choisir une seule valeur dans un fichier yaml.
Par exemple, si vous avez ces fichiers yaml:
staging.yaml:
prod.yaml:
Vous pouvez charger les deux sans conflit.
Et même cerise sur le gâteau, choisissez les valeurs que vous souhaitez.
la source
Vous pouvez utiliser un équivalent de yq écrit en golang:
Retour:
la source
Vous pouvez également envisager d'utiliser Grunt (The JavaScript Task Runner). Peut être facilement intégré à la coque. Il prend en charge la lecture des fichiers YAML (
grunt.file.readYAML
) et JSON (grunt.file.readJSON
).Ceci peut être réalisé en créant une tâche dans
Gruntfile.js
(ouGruntfile.coffee
), par exemple:puis à partir du shell, exécutez simplement
grunt foo
(vérifiezgrunt --help
les tâches disponibles).De plus, vous pouvez implémenter des
exec:foo
tâches (grunt-exec
) avec des variables d'entrée passées de votre tâche (foo: { cmd: 'echo bar <%= foo %>' }
) afin d'imprimer la sortie dans le format de votre choix, puis la diriger vers une autre commande.Il existe également un outil similaire à Grunt, il s'appelle gulp avec le plugin supplémentaire gulp-yaml .
Installer via:
npm install --save-dev gulp-yaml
Exemple d'utilisation:
Pour plus d'options pour gérer le format YAML , consultez le site YAML pour les projets, bibliothèques et autres ressources disponibles qui peuvent vous aider à analyser ce format.
Autres outils:
Jshon
la source
Je sais que ma réponse est spécifique, mais si PHP et Symfony sont déjà installés, il peut être très pratique d'utiliser l'analyseur YAML de Symfony.
Par exemple:
Ici, j'ai simplement utilisé
var_dump
pour sortir le tableau analysé mais bien sûr, vous pouvez faire beaucoup plus ... :)la source