Chciałbym dostarczyć ustrukturyzowany plik konfiguracyjny, który jest jak najłatwiejszy do edycji dla nietechnicznego użytkownika (niestety musi to być plik), więc chciałem użyć YAML. Nie mogę jednak znaleźć sposobu na parsowanie tego ze skryptu powłoki Uniksa.
193
yq
do odczytu / zapisu plików yaml w powłoce. Na stronie projektu znajduje się tutaj: mikefarah.github.io/yq można zainstalować narzędzie zbrew
,apt
lub pobrać plik binarny. Odczyt wartości jest tak prosty, jakyq r some.yaml key.value
Odpowiedzi:
Mój przypadek użycia może, ale nie musi być taki sam, jak ten, o który pytał ten oryginalny post, ale jest zdecydowanie podobny.
Muszę pobrać trochę YAML jako zmienne bash. YAML nigdy nie będzie głębszy niż jeden poziom.
YAML wygląda tak:
Wyjście jak dis:
Osiągnąłem wynik dzięki tej linii:
s/:[^:\/\/]/="/g
znajduje:
i zamienia go="
, ignorując://
(w przypadku adresów URL)s/$/"/g
dołącza"
na końcu każdej liniis/ *=/=/g
usuwa wszystkie spacje wcześniej=
źródło
{KEY: 'value', ...}
; i ewentualnie inni. Co najważniejsze, jeśli zamierzasz ocenić wynik jako kod powłoki, byłoby to bardzo niepewne.Oto analizator składający się tylko z basha, który wykorzystuje sed i awk do analizowania prostych plików yaml:
Rozumie pliki takie jak:
Które po przeanalizowaniu za pomocą:
wyświetli:
rozumie również pliki yaml, generowane przez ruby, które mogą zawierać symbole ruby, takie jak:
i wyświetli to samo, co w poprzednim przykładzie.
typowe zastosowanie w skrypcie to:
parse_yaml przyjmuje argument przedrostka, dzięki czemu wszystkie importowane ustawienia mają wspólny przedrostek (co zmniejsza ryzyko kolizji w przestrzeni nazw).
daje:
Pamiętaj, że do poprzednich ustawień w pliku można odwoływać się w późniejszych ustawieniach:
Innym miłym zastosowaniem jest najpierw parsowanie pliku domyślnego, a następnie ustawień użytkownika, co działa, ponieważ te ostatnie zastępują pierwsze:
źródło
-
notację yaml w rodzime tablice bash!global__debug
Zamiastglobal_debug
.Napisałem
shyaml
w pythonie dla potrzeb zapytania YAML z wiersza poleceń powłoki.Przegląd:
Przykładowy plik YAML (ze złożonymi funkcjami):
Podstawowe zapytanie:
Bardziej złożone zapytanie o zapętlenie dotyczące złożonych wartości:
Kilka kluczowych punktów:
\0
wyściełane wyjście jest dostępne do solidnego manipulowania wejściem wielowierszowym.subvalue.maintainer
jest prawidłowym kluczem).subvalue.things.-1
jest ostatnim elementemsubvalue.things
sekwencji).Więcej próbek i dokumentacji dostępnych jest na stronie nieśmiałyaml github lub stronie nieśmiałyam PyPI .
źródło
cat docker-compose.yml | shyaml get-value api.environment | grep -v null | awk -F': ' '{print $2 > ("envdir/" $1)}'
shyaml
jest absurdalnie wolny( https://github.com/mikefarah/yq#readme )
Jako przykład (skradziony bezpośrednio z dokumentacji ) podano przykładowy plik:
następnie
wyjdzie
źródło
Możliwe jest przekazanie małego skryptu niektórym tłumaczom, takim jak Python. Prostym sposobem na to przy użyciu Ruby i jego biblioteki YAML jest:
, gdzie
data
jest skrót (lub tablica) z wartościami yaml.Jako bonus dokładnie przeanalizuje przód Jekylla .
źródło
RUBY_SCRIPT
Zmienna jest skrypt Ruby, które mogą być zapisane do pliku zamiast biegu (zruby -ryaml <rubyscript_filename>
). Zawiera logikę przekształcania tekstu wejściowego na tekst wyjściowy, wewnętrznie przechowując zawartość wdata
zmiennej. Echo generuje tekst yaml, alecat <yaml_filename>
zamiast tego możesz użyć do potokowania zawartości pliku.stdout
zasilać zmienną, nie musisz polegać na pliki tymczasowe! użyjx=$(...)
lub nawetread a b c < <(...)
). Jest to więc prawidłowe rozwiązanie, gdy wiesz dokładnie, co chcesz pobrać z pliku YAML i wiesz, jak napisać ruby, aby uzyskać dostęp do tych danych. Nawet jeśli jest szorstki, jest to pełny dowód koncepcji IMHO. Prawdą jest jednak, że nie zapewnia pełnej abstrakcji.Biorąc pod uwagę, że Python3 i PyYAML są dość łatwymi zależnościami do spełnienia w dzisiejszych czasach, mogą pomóc:
źródło
yaml.safe_load
ponieważ jest bezpieczniejszy. pyyaml.org/wiki/PyYAMLDokumentacjatutaj rozszerzona wersja odpowiedzi Stefana Farestama:
Ta wersja obsługuje
-
notację i krótką notację dla słowników i list. Następujące dane wejściowe:tworzy ten wynik:
jak widać,
-
pozycje są automatycznie numerowane w celu uzyskania różnych nazw zmiennych dla każdego elementu. Wbash
tym przypadku nie ma tablic wielowymiarowych, więc jest to jeden ze sposobów obejścia problemu. Obsługiwanych jest wiele poziomów. Aby obejść problem z końcowymi spacjami wymienionymi przez @briceburg, należy zawrzeć wartości w pojedynczych lub podwójnych cudzysłowach. Nadal istnieją jednak pewne ograniczenia: rozszerzenie słowników i list może dawać nieprawidłowe wyniki, gdy wartości zawierają przecinki. Ponadto bardziej złożone struktury, takie jak wartości obejmujące wiele linii (jak klucze ssh), nie są (jeszcze) obsługiwane.Kilka słów o kodzie: Pierwsze
sed
polecenie rozszerza krótką formę słowników{ key: value, ...}
na zwykłe i konwertuje je na prostszy styl yaml. Drugiesed
wywołanie robi to samo w przypadku krótkiej notacji list i konwertuje[ entry, ... ]
do listy pozycji z-
notacją. Trzeciesed
wywołanie jest oryginalne, które obsługuje normalne słowniki, teraz z dodatkiem do obsługi list z-
wcięciami.awk
Część wprowadza indeks dla każdego poziomu wcięcia i zwiększa się ją, gdy nazwa zmienna jest pusta (czyli podczas przetwarzania listy). Zamiast pustej nazwy używana jest bieżąca wartość liczników. Podczas wchodzenia o jeden poziom liczniki są zerowane.Edycja: Utworzyłem do tego repozytorium github .
źródło
Trudno powiedzieć, ponieważ zależy to od tego, co parser ma wyodrębnić z dokumentu YAML. W prostych przypadkach, może być w stanie wykorzystać
grep
,cut
,awk
itd. W przypadku bardziej złożonych parsowania trzeba by użyć pełnowymiarową analizowania takich jak biblioteka Pythona PyYAML lub YAML :: Perl .źródło
Właśnie napisałem parser, który nazwałem Yay! ( Yaml to nie Jamlesque! ), Który analizuje Yamlesque , niewielki podzbiór YAML. Jeśli więc szukasz parsera YAML w 100% zgodnego z Bash, to nie o to chodzi. Jednak, aby zacytować OP, jeśli chcesz ustrukturyzowanego pliku konfiguracyjnego, który jest jak najłatwiejszy dla użytkownika nietechnicznego, który jest podobny do YAML, może to być interesujące.
Jest inspirowany wcześniejszą odpowiedzią, ale zapisuje tablice asocjacyjne ( tak, wymaga Bash 4.x ) zamiast podstawowych zmiennych. Robi to w sposób, który pozwala na parsowanie danych bez uprzedniej wiedzy o kluczach, aby można było napisać kod sterowany danymi.
Oprócz elementów tablicy klucz / wartość każda tablica ma
keys
tablicę zawierającą listę nazw kluczy,children
tablicę zawierającą nazwy tablic podrzędnych iparent
klucz, który odnosi się do jego elementu nadrzędnego.To jest przykład Yamlesque:
Oto przykład pokazujący, jak z niego korzystać:
które wyjścia:
A oto parser:
W połączonym pliku źródłowym znajduje się dokumentacja, a poniżej znajduje się krótkie objaśnienie działania kodu.
yay_parse
Funkcja najpierw lokalizujeinput
plik lub wyjścia ze stanem wyjściowym 1. Następnie, określa zbiór danychprefix
, albo wyraźnie określony lub pochodzącą od nazwy pliku.Zapisuje prawidłowe
bash
polecenia na swoim standardowym wyjściu, które, jeśli zostaną wykonane, definiują tablice reprezentujące zawartość pliku danych wejściowych. Pierwszy z nich określa tablicę najwyższego poziomu:Zauważ, że deklaracje tablicowe są stowarzyszone (
-A
), co jest cechą wersji Bash 4. Deklaracje są również globalne (-g
), więc można je wykonywać w funkcji, ale być dostępne dla zakresu globalnego, takiego jakyay
pomocnik:Dane wejściowe są wstępnie przetwarzane za pomocą
sed
. Porzuca linie, które nie pasują do specyfikacji formatu Yamlesque, przed rozdzieleniem prawidłowych pól Yamlesque znakiem separatora plików ASCII i usunięciem podwójnych cudzysłowów otaczających pole wartości.Te dwa wyrażenia są podobne; różnią się tylko tym, że pierwszy wybiera wartości cytowane, a drugi wybiera niecytowane.
File Separator (28 / hex 12 / ósemkowy 034) służy, bo jak niedrukowalny charakterem, jest mało prawdopodobne, aby być w danych wejściowych.
Wynik jest przesyłany do procesora,
awk
który przetwarza dane wejściowe pojedynczo. Używa znaku FS, aby przypisać każde pole do zmiennej:Wszystkie linie mają wcięcie (prawdopodobnie zero) i klucz, ale nie wszystkie mają wartość. Oblicza poziom wcięcia dla linii dzielącej długość pierwszego pola zawierającego wiodące białe znaki przez dwa. Elementy najwyższego poziomu bez wcięcia znajdują się na poziomie wcięcia zero.
Następnie zastanawia się, czego
prefix
użyć dla bieżącego elementu. To jest dodawane do nazwy klucza, aby utworzyć nazwę tablicy. Istniejeroot_prefix
tablica najwyższego poziomu, która jest zdefiniowana jako nazwa zestawu danych i znak podkreślenia:Jest
parent_key
to klucz na poziomie wcięcia powyżej poziomu wcięcia bieżącej linii i reprezentuje kolekcję, której częścią jest bieżąca linia. Pary klucz / wartość kolekcji zostaną zapisane w tablicy o nazwie zdefiniowanej jako konkatenacjaprefix
iparent_key
.W przypadku najwyższego poziomu (poziom wcięcia zero) prefiks zestawu danych jest używany jako klucz nadrzędny, więc nie ma on prefiksu (jest ustawiony na
""
). Wszystkie pozostałe tablice są poprzedzone prefiksem głównym.Następnie bieżący klucz jest wstawiany do (awk-wewnętrznej) tablicy zawierającej klucze. Tablica ta utrzymuje się przez całą sesję awk i dlatego zawiera klucze wstawiane przez wcześniejsze linie. Klucz jest wstawiany do tablicy za pomocą jego wcięcia jako indeksu tablicy.
Ponieważ ta tablica zawiera klucze z poprzednich linii, wszelkie klucze z wyższym poziomem wcięcia niż poziom wcięcia bieżącej linii są usuwane:
Pozostawia to tablicę kluczy zawierającą łańcuch kluczy od korzenia na poziomie wcięcia 0 do bieżącej linii. Usuwa przestarzałe klucze, które pozostają, gdy poprzednia linia została wcięta głębiej niż bieżąca linia.
Ostatnia sekcja zawiera
bash
polecenia: linia wejściowa bez wartości rozpoczyna nowy poziom wcięcia ( zbiór w języku YAML), a linia wejściowa z wartością dodaje klucz do bieżącej kolekcji.Nazwa kolekcji to konkatenacja bieżącej linii
prefix
iparent_key
.Gdy klucz ma wartość, klucz o tej wartości jest przypisywany do bieżącej kolekcji w następujący sposób:
Pierwsza instrukcja wypisuje polecenie przypisania wartości do elementu tablicy asocjacyjnej nazwanej po kluczu, a druga wypisuje polecenie dodania klucza do
keys
listy rozdzielanej spacjami kolekcji :Gdy klucz nie ma wartości, rozpoczyna się nowa kolekcja w następujący sposób:
Pierwsza instrukcja wypisuje polecenie dodania nowej kolekcji do
children
listy rozdzielanej spacjami kolekcji bieżącej, a druga wypisuje polecenie zadeklarowania nowej tablicy asocjacyjnej dla nowej kolekcji:Wszystkie dane wyjściowe z
yay_parse
mogą być analizowane jako polecenia bash przez basheval
lubsource
wbudowane polecenia.źródło
examples
iusr/lib
katalogów, są one połączone w mojej odpowiedzi na pytanie. Jeśli jest zainteresowanie, mógłbym je rozbić na własne repozytorium.źródło
Inną opcją jest konwersja YAML na JSON, a następnie użycie jq do interakcji z reprezentacją JSON w celu wydobycia z niej informacji lub ich edycji.
Napisałem prosty skrypt bash, który zawiera ten klej - patrz projekt Y2J na GitHub
źródło
Jeśli potrzebujesz jednej wartości, możesz użyć narzędzia, które konwertuje twój dokument YAML na JSON i podaje
jq
na przykład plik danychyq
.Zawartość sample.yaml:
Przykład:
źródło
Wiem, że jest to bardzo specyficzne, ale myślę, że moja odpowiedź może być pomocna dla niektórych użytkowników.
Jeśli masz
node
inpm
zainstalowałeś na swoim komputerze, możesz użyćjs-yaml
.Pierwsza instalacja:
następnie w skrypcie bash
Również jeśli używasz
jq
, możesz zrobić coś takiegoPonieważ
js-yaml
konwertuje plik yaml na dosłowny ciąg json. Następnie możesz użyć łańcucha z dowolnym parserem json w systemie uniksowym.źródło
Jeśli masz Python 2 i PyYAML, możesz użyć tego analizatora składni, który napisałem o nazwie parse_yaml.py . Jedną z fajniejszych rzeczy, jakie robi, jest wybranie prefiksu (w przypadku, gdy masz więcej niż jeden plik z podobnymi zmiennymi) i wybranie pojedynczej wartości z pliku yaml.
Na przykład, jeśli masz te pliki yaml:
staging.yaml:
prod. yaml:
Możesz załadować oba bez konfliktu.
Nawet wiśnia wybiera wartości, które chcesz.
źródło
Można użyć odpowiednik z yq , co jest napisane w golang:
zwroty:
źródło
Możesz również rozważyć użycie Grunt (JavaScript Task Runner). Może być łatwo zintegrowany z powłoką. Obsługuje odczytywanie plików YAML (
grunt.file.readYAML
) i JSON (grunt.file.readJSON
).Można to osiągnąć, tworząc zadanie w
Gruntfile.js
(lubGruntfile.coffee
), np .:następnie z poziomu powłoki wystarczy po prostu uruchomić
grunt foo
(sprawdźgrunt --help
dostępne zadania).Co więcej, możesz zaimplementować
exec:foo
zadania (grunt-exec
) ze zmiennymi wejściowymi przekazanymi z zadania (foo: { cmd: 'echo bar <%= foo %>' }
) w celu wydrukowania wyniku w dowolnym formacie, a następnie potokowanie go do innego polecenia.Istnieje również podobne narzędzie do Grunta, nazywa się gulp z dodatkową wtyczką gulp-yaml .
Zainstaluj przez:
npm install --save-dev gulp-yaml
Przykładowe użycie:
Aby uzyskać więcej opcji radzenia sobie z formatem YAML , sprawdź witrynę YAML pod kątem dostępnych projektów, bibliotek i innych zasobów, które mogą pomóc w analizie tego formatu.
Inne narzędzia:
Jshon
źródło
Wiem, że moja odpowiedź jest konkretna, ale jeśli ktoś już ma zainstalowane PHP i Symfony , bardzo przydatne może być użycie parsera YAML Symfony.
Na przykład:
Tutaj po prostu użyłem
var_dump
danych wyjściowych przeanalizowanej tablicy, ale oczywiście możesz zrobić znacznie więcej ... :)źródło