Ich möchte eine strukturierte Konfigurationsdatei bereitstellen, die für einen nicht technischen Benutzer so einfach wie möglich zu bearbeiten ist (leider muss es sich um eine Datei handeln), und wollte daher YAML verwenden. Ich kann jedoch keine Möglichkeit finden, dies aus einem Unix-Shell-Skript zu analysieren.
192
yq
, Yaml-Dateien in der Shell zu lesen / schreiben. Die Projektseite ist hier: mikefarah.github.io/yq Sie können das Tool mit installierenbrew
,apt
oder laden Sie die binäre. Das Lesen eines Wertes ist so einfach wieyq r some.yaml key.value
Antworten:
Mein Anwendungsfall kann oder kann nicht ganz der sein, den dieser ursprüngliche Beitrag verlangt hat, aber es ist definitiv ähnlich.
Ich muss einige YAML als Bash-Variablen einfügen. Die YAML wird niemals mehr als eine Ebene tief sein.
YAML sieht so aus:
Ausgabe wie ein Dis:
Ich habe die Ausgabe mit dieser Zeile erreicht:
s/:[^:\/\/]/="/g
findet:
und ersetzt es durch="
, während ignoriert://
(für URLs)s/$/"/g
wird"
an das Ende jeder Zeile angehängts/ *=/=/g
entfernt alle Leerzeichen vor=
quelle
{KEY: 'value', ...}
; und möglicherweise andere. Wenn Sie das Ergebnis als Shell-Code auswerten möchten, ist dies vor allem sehr unsicher.Hier ist ein Nur-Bash-Parser, der sed und awk nutzt, um einfache Yaml-Dateien zu analysieren:
Es versteht Dateien wie:
Welche, wenn analysiert mit:
wird ausgegeben:
Es versteht auch Yaml-Dateien, die von Ruby generiert wurden und Rubinsymbole enthalten können, wie:
und gibt das gleiche wie im vorherigen Beispiel aus.
Typische Verwendung innerhalb eines Skripts ist:
parse_yaml akzeptiert ein Präfixargument, sodass alle importierten Einstellungen ein gemeinsames Präfix haben (wodurch das Risiko von Namespace-Kollisionen verringert wird).
Ausbeuten:
Beachten Sie, dass auf frühere Einstellungen in einer Datei durch spätere Einstellungen verwiesen werden kann:
Eine weitere nützliche Verwendung besteht darin, zuerst eine Standarddatei und dann die Benutzereinstellungen zu analysieren. Dies funktioniert, da die letzteren Einstellungen die ersten überschreiben:
quelle
-
Notation auch in native Bash-Arrays verwandeln könnte !global__debug
anstelle vonglobal_debug
.Ich habe
shyaml
in Python für YAML-Abfragebedürfnisse über die Shell-Befehlszeile geschrieben.Überblick:
Beispiel YAML-Datei (mit komplexen Funktionen):
Grundlegende Abfrage:
Komplexere Schleifenabfrage für komplexe Werte:
Einige wichtige Punkte:
\0
Die gepolsterte Ausgabe ist für die Manipulation von mehrzeiligen Einträgen verfügbar.subvalue.maintainer
ist ein gültiger Schlüssel).subvalue.things.-1
ist das letzte Element dersubvalue.things
Sequenz.)Weitere Beispiele und Dokumentationen finden Sie auf der Shyaml-Github-Seite oder der Shyaml-PyPI-Seite .
quelle
cat docker-compose.yml | shyaml get-value api.environment | grep -v null | awk -F': ' '{print $2 > ("envdir/" $1)}'
shyaml
ist lächerlich langsam( https://github.com/mikefarah/yq#readme )
Als Beispiel (direkt aus der Dokumentation gestohlen ) mit einer sample.yaml-Datei von:
dann
wird ausgegeben
quelle
Es ist möglich, ein kleines Skript an einige Interpreten wie Python zu übergeben. Eine einfache Möglichkeit, dies mit Ruby und seiner YAML-Bibliothek zu tun, ist die folgende:
, wo
data
ist ein Hash (oder Array) mit den Werten von yaml.Als Bonus wird Jekylls vordere Angelegenheit ganz gut analysiert .
quelle
RUBY_SCRIPT
Variable ist ein Ruby-Skript, das stattdessen in eine Datei geschrieben werden kann (ausgeführt mitruby -ryaml <rubyscript_filename>
). Es enthält die Logik, den Eingabetext in einen Ausgabetext umzuwandeln und den Inhalt intern in derdata
Variablen zu speichern . Das Echo gibt einen Yaml-Text aus, aber Sie könnencat <yaml_filename>
stattdessen den Inhalt einer Datei weiterleiten .stdout
, um in eine Variable eingespeist zu werden, müssen Sie sich nicht darauf verlassen temporäre Dateien! verwendenx=$(...)
oder sogarread a b c < <(...)
). Dies ist also eine gültige Lösung, wenn Sie genau wissen, was Sie in der YAML-Datei abrufen möchten, und wissen, wie Sie die Rubinlinien schreiben, um auf diese Daten zuzugreifen. Auch wenn es rau ist, ist es meiner Meinung nach ein vollständiger Proof of Concept der Idee. Es ist jedoch wahr, dass es Ihnen keine vollständige Bash-Abstraktion bietet.Angesichts der Tatsache, dass Python3 und PyYAML heutzutage recht einfache Abhängigkeiten sind, kann Folgendes helfen:
quelle
yaml.safe_load
da es sicherer ist. pyyaml.org/wiki/PyYAMLDocumentationhier eine erweiterte Version der Antwort von Stefan Farestam:
Diese Version unterstützt die
-
Notation und die Kurznotation für Wörterbücher und Listen. Die folgende Eingabe:erzeugt diese Ausgabe:
Wie Sie sehen können, werden die
-
Elemente automatisch nummeriert, um unterschiedliche Variablennamen für jedes Element zu erhalten. Inbash
es keine mehrdimensionale Arrays ist, so ist dies ein Weg , um zu arbeiten. Es werden mehrere Ebenen unterstützt. Um das von @briceburg erwähnte Problem mit nachgestellten Leerzeichen zu umgehen, sollten die Werte in einfache oder doppelte Anführungszeichen gesetzt werden. Es gibt jedoch noch einige Einschränkungen: Die Erweiterung der Wörterbücher und Listen kann zu falschen Ergebnissen führen, wenn Werte Kommas enthalten. Komplexere Strukturen wie Werte, die sich über mehrere Zeilen erstrecken (wie z. B. SSH-Schlüssel), werden (noch) nicht unterstützt.Ein paar Worte zum Code: Der erste
sed
Befehl erweitert die Kurzform der Wörterbücher{ key: value, ...}
auf regulär und konvertiert sie in einen einfacheren Yaml-Stil. Der zweitesed
Aufruf macht dasselbe für die Kurznotation von Listen und konvertiert[ entry, ... ]
in eine detaillierte Liste mit der-
Notation. Der drittesed
Aufruf ist der ursprüngliche Aufruf, der normale Wörterbücher handhabte, jetzt mit dem Zusatz, Listen mit-
und Einrückungen zu behandeln. Derawk
Teil führt einen Index für jede Einrückungsstufe ein und erhöht ihn, wenn der Variablenname leer ist (dh wenn eine Liste verarbeitet wird). Der aktuelle Wert der Zähler wird anstelle des leeren vnamens verwendet. Wenn Sie eine Ebene höher gehen, werden die Zähler auf Null gesetzt.Bearbeiten: Ich habe dafür ein Github-Repository erstellt .
quelle
Schwer zu sagen, da es davon abhängt, was der Parser aus Ihrem YAML-Dokument extrahieren soll. Für einfache Fälle, könnten Sie in der Lage sein zu verwenden
grep
,cut
,awk
usw. Für komplexere Parsing Sie eine ausgewachsene verwenden Parsing - Bibliothek wie Python benötigen würde PyYAML oder YAML :: Perl .quelle
Ich habe gerade einen Parser geschrieben, den ich Yay! ( Yaml ist nicht Yamlesque! ), Das Yamlesque analysiert , eine kleine Untergruppe von YAML. Wenn Sie also nach einem 100% kompatiblen YAML-Parser für Bash suchen, ist dies nicht der Fall. Um das OP zu zitieren: Wenn Sie eine strukturierte Konfigurationsdatei wünschen, die für einen nicht technischen Benutzer so einfach wie möglich zu bearbeiten ist und die YAML-ähnlich ist, kann dies von Interesse sein.
Es ist von der früheren Antwort geprägt , schreibt aber assoziative Arrays ( ja, es erfordert Bash 4.x ) anstelle von Basisvariablen. Dies geschieht so, dass die Daten ohne vorherige Kenntnis der Schlüssel analysiert werden können, sodass datengesteuerter Code geschrieben werden kann.
Neben den Schlüssel- / Wert-Array-Elementen verfügt jedes Array über ein
keys
Array mit einer Liste von Schlüsselnamen, einchildren
Array mit Namen von untergeordneten Arrays und einenparent
Schlüssel, der auf das übergeordnete Array verweist.Dies ist ein Beispiel für Yamlesque:
Hier ist ein Beispiel, das zeigt, wie man es benutzt:
welche Ausgänge:
Und hier ist der Parser:
Die verknüpfte Quelldatei enthält einige Dokumentationen. Nachfolgend finden Sie eine kurze Erläuterung der Funktionsweise des Codes.
Die
yay_parse
Funktion sucht zuerst dieinput
Datei oder beendet sie mit einem Exit-Status von 1. Anschließend ermittelt sie das Datasetprefix
, das entweder explizit angegeben oder vom Dateinamen abgeleitet ist.Es schreibt gültige
bash
Befehle in seine Standardausgabe, die bei Ausführung Arrays definieren, die den Inhalt der Eingabedatendatei darstellen. Die erste davon definiert das Array der obersten Ebene:Beachten Sie, dass Array-Deklarationen assoziativ (
-A
) sind, was eine Funktion von Bash Version 4 ist. Deklarationen sind ebenfalls global (-g
), sodass sie in einer Funktion ausgeführt werden können, aber für den globalen Bereich wie deryay
Helfer verfügbar sind :Die Eingabedaten werden zunächst mit verarbeitet
sed
. Es fällt Zeilen , die mit einem ASCII vor abgrenzt die gültigen Yamlesque Felder nicht die Formatspezifikation Yamlesque entsprechen Datei Separator Zeichen und Entfernen aller doppelten Anführungszeichen rund um das Wertefeld.Die beiden Ausdrücke sind ähnlich; Sie unterscheiden sich nur, weil der erste zitierte Werte auswählt, während der zweite nicht zitierte Werte auswählt.
Der Dateitrenner (28 / hex 12 / octal 034) wird verwendet, da er als nicht druckbares Zeichen wahrscheinlich nicht in den Eingabedaten enthalten ist.
Das Ergebnis wird weitergeleitet, in
awk
das die Eingabe zeilenweise verarbeitet wird. Es verwendet das FS- Zeichen, um jedes Feld einer Variablen zuzuweisen:Alle Zeilen haben einen Einzug (möglicherweise Null) und einen Schlüssel, aber nicht alle haben einen Wert. Es wird eine Einrückungsstufe für die Linie berechnet, die die Länge des ersten Felds, das das führende Leerzeichen enthält, durch zwei teilt. Die Elemente der obersten Ebene ohne Einzug befinden sich auf der Einzugsebene Null.
Als nächstes wird herausgefunden, was
prefix
für das aktuelle Element verwendet werden soll. Dies wird einem Schlüsselnamen hinzugefügt, um einen Array-Namen zu erstellen. Es gibt einroot_prefix
Array für die oberste Ebene, das als Datensatzname und Unterstrich definiert ist:Das
parent_key
ist der Schlüssel auf der Einrückungsstufe über der Einrückungsstufe der aktuellen Zeile und repräsentiert die Sammlung, zu der die aktuelle Zeile gehört. Die Schlüssel / Wert-Paare der Sammlung werden in einem Array gespeichert, dessen Name als Verkettung vonprefix
und definiert istparent_key
.Für die oberste Ebene (Einzugsebene Null) wird das Datensatzpräfix als übergeordneter Schlüssel verwendet, sodass es kein Präfix hat (es ist auf gesetzt
""
). Allen anderen Arrays wird das Root-Präfix vorangestellt.Als nächstes wird der aktuelle Schlüssel in ein (awk-internes) Array eingefügt, das die Schlüssel enthält. Dieses Array bleibt während der gesamten awk-Sitzung bestehen und enthält daher Schlüssel, die durch vorherige Zeilen eingefügt wurden. Der Schlüssel wird mit seinem Einzug als Array-Index in das Array eingefügt.
Da dieses Array Schlüssel aus vorherigen Zeilen enthält, werden alle Schlüssel entfernt, deren Einrückungsstufe größer als die Einrückungsstufe der aktuellen Zeile ist:
Dadurch bleibt das Schlüsselarray mit der Schlüsselkette vom Stamm auf Einrückungsstufe 0 bis zur aktuellen Zeile. Es werden veraltete Schlüssel entfernt, die verbleiben, wenn die vorherige Zeile tiefer als die aktuelle Zeile eingerückt wurde.
Der letzte Abschnitt gibt die
bash
Befehle aus: Eine Eingabezeile ohne Wert startet eine neue Einrückungsstufe (eine Sammlung im YAML-Sprachgebrauch) und eine Eingabezeile mit einem Wert fügt der aktuellen Sammlung einen Schlüssel hinzu.Der Name der Sammlung ist die Verkettung der aktuellen Zeilen
prefix
undparent_key
.Wenn ein Schlüssel einen Wert hat, wird der aktuellen Sammlung ein Schlüssel mit diesem Wert wie folgt zugewiesen:
Die erste Anweisung gibt den Befehl zum Zuweisen des Werts zu einem nach dem Schlüssel benannten assoziativen Array-Element aus, und die zweite gibt den Befehl zum Hinzufügen des Schlüssels zur durch Leerzeichen getrennten
keys
Liste der Sammlung aus :Wenn ein Schlüssel keinen Wert hat, wird eine neue Sammlung wie folgt gestartet:
Die erste Anweisung gibt den Befehl zum Hinzufügen der neuen Sammlung zur durch Leerzeichen getrennten
children
Liste der aktuellen Sammlung aus, und die zweite gibt den Befehl zum Deklarieren eines neuen assoziativen Arrays für die neue Sammlung aus:Die gesamte Ausgabe von
yay_parse
kann von den Bash-eval
odersource
integrierten Befehlen als Bash-Befehle analysiert werden.quelle
examples
undusr/lib
Verzeichnisse, Diese sind in meiner Antwort auf die Frage verlinkt. Wenn es Interesse gibt, könnte ich es in ein eigenes Repo aufteilen.quelle
Eine andere Möglichkeit besteht darin, die YAML in JSON zu konvertieren und dann mit jq mit der JSON-Darstellung zu interagieren, um entweder Informationen daraus zu extrahieren oder sie zu bearbeiten.
Ich habe ein einfaches Bash-Skript geschrieben, das diesen Kleber enthält - siehe Y2J-Projekt auf GitHub
quelle
Wenn Sie einen einzelnen Wert brauchen Sie ein Werkzeug , das Ihr YAML Dokument zu JSON konvertiert und Futtermittel
jq
, zum Beispielyq
.Inhalt von sample.yaml:
Beispiel:
quelle
Ich weiß, dass dies sehr spezifisch ist, aber ich denke, meine Antwort könnte für bestimmte Benutzer hilfreich sein.
Wenn Sie
node
undnpm
auf Ihrem Computer installiert haben , können Sie verwendenjs-yaml
.Erste Installation:
dann in Ihrem Bash-Skript
Auch wenn Sie verwenden
jq
, können Sie so etwas tunWeil
js-yaml
eine yaml-Datei in ein json-String-Literal konvertiert. Sie können die Zeichenfolge dann mit jedem JSON-Parser in Ihrem Unix-System verwenden.quelle
Wenn Sie Python 2 und PyYAML haben, können Sie diesen von mir geschriebenen Parser namens parse_yaml.py verwenden . Einige der übersichtlicheren Dinge sind, dass Sie ein Präfix auswählen können (falls Sie mehr als eine Datei mit ähnlichen Variablen haben) und einen einzelnen Wert aus einer Yaml-Datei auswählen.
Zum Beispiel, wenn Sie diese Yaml-Dateien haben:
staging.yaml:
prod.yaml:
Sie können beide ohne Konflikte laden.
Und sogar Kirsche wählen Sie die Werte, die Sie wollen.
quelle
Sie könnten ein Äquivalent von yq verwenden , das in Golang geschrieben ist:
kehrt zurück:
quelle
Sie können auch Grunt (The JavaScript Task Runner) verwenden. Kann leicht in die Shell integriert werden. Es unterstützt das Lesen von YAML (
grunt.file.readYAML
) - und JSON (grunt.file.readJSON
) -Dateien.Dies kann erreicht werden, indem eine Aufgabe in
Gruntfile.js
(oderGruntfile.coffee
) erstellt wird, z.dann einfach von der Shell ausführen
grunt foo
(grunt --help
auf verfügbare Aufgaben prüfen ).Darüber hinaus können Sie
exec:foo
task (grunt-exec
) mit Eingabevariablen implementieren , die von Ihrer task (foo: { cmd: 'echo bar <%= foo %>' }
) übergeben wurden, um die Ausgabe in einem beliebigen Format zu drucken und dann in einen anderen Befehl weiterzuleiten.Es gibt auch ein ähnliches Tool wie Grunt, es heißt gulp mit zusätzlichem Plugin gulp-yaml .
Installation über:
npm install --save-dev gulp-yaml
Beispielnutzung:
Weitere Optionen für das YAML-Format finden Sie auf der YAML-Website nach verfügbaren Projekten, Bibliotheken und anderen Ressourcen, mit denen Sie dieses Format analysieren können.
Andere Werkzeuge:
Jshon
quelle
Ich weiß, dass meine Antwort spezifisch ist, aber wenn PHP und Symfony bereits installiert sind, kann es sehr praktisch sein, den YAML-Parser von Symfony zu verwenden.
Zum Beispiel:
Hier habe ich einfach
var_dump
das analysierte Array ausgegeben, aber natürlich können Sie noch viel mehr ... :)quelle