Przeanalizuj ciąg w skrypcie bash

Przejrzałem inne odpowiedzi, ale nie mogłem uzyskać odpowiedniego wyjaśnienia, jak to zrobić.

I mieć zmienną łańcuchową o nazwie id taką, że id="{"name":"john"}". Jak mogę uzyskać 2 zmienne z tego ciągu, takie jak-

key="name" value="john" 

Szczegółowe wyjaśnienie byłoby mile widziane, ponieważ chcę zrozumieć parsowanie ciągów w bash.

Do tej pory usunąłem nawiasy klamrowe {} z ciągu-

id="$( echo "${id}" | tr -d {} )" 

Nie mogę umieścić w nim " jako generuje błąd. Poszukuje też czegoś takiego jak id.split(":") na końcu, aby uzyskać tablicę.

Komentarze

  • Czy możemy Cię ostrzec przed tą taktyką / ścieżką, zanim ' będzie za późno? Wygląda na to, że masz json lub inne ustrukturyzowane dane. Być może dedykowane narzędzie będzie bezpieczniejszy sposób na dotarcie tam, gdzie jedziemy?
  • Widziałem, że jq jest używane przez innych, ale czy nie ma możliwości, żebym mógł to przeanalizować bez osoby trzeciej narzędzie?
  • Czy przenosisz te dane z pliku? Czy może istnieć więcej niż jedna para klucz / wartość? Jak mógłby wyglądać cudzysłów jako część wartości?
  • @kev: technicznie awk, sed i grep to również narzędzia innych firm. Jeśli używasz danych json, nie ma absolutnie żadnego powodu, aby nie mieć odpowiednich narzędzi do pracy z nimi.
  • Te dane są wynikiem polecenia, wykonane w moim skrypcie. Zawsze będzie w tym formacie – 1 klucz i 1 wartość.

Odpowiedź

Używając jq:

id="{"name":"john"}" key=$(jq -r keys[] <<<"$id") value=$(jq -r .[] <<<"$id") 

-r: Z tą opcją, jeśli filtr „s wynik jest ciągiem, a następnie zostanie zapisany bezpośrednio na standardowe wyjście, a nie sformatowany jako ciąg JSON w cudzysłowach.

keys: Wbudowane klawisze funkcyjne, gdy po otrzymaniu obiektu zwraca jego klucze w tablicy.


Używanie json:

id="{"name":"john"}" key=$(json -ak <<<"$id") value=$(json -a "$key" <<<"$id") 

-a przetwarza dane wejściowe jako tablicę

-k zwraca wartości kluczy

Komentarze

  • Dziękuję za wyjaśnienie. Działa świetnie. Myślę, że ' nie ma możliwości przeanalizowania ciągu bez jq w skryptach basha.
  • @kev: Jest wiele sposobów analizowania ciągów, ale jest to ' trochę niesprawiedliwe aby nazwać to ciągiem znaków, a nie danymi json.
  • @kev Dane JSON mogą być kodowane. Aby go przeanalizować, potencjalnie musiałbyś go zdekodować. Ponadto JSON nie dba o białe znaki (znaki nowej linii itp.) Między kluczami i wartościami, więc musisz to wziąć pod uwagę. Zostało to już zrobione przez autorów bazowego parsera JSON w jq.

Odpowiedź

Dosłownie prosiłeś o understand string parsing in bash, więc napiszę odpowiedź, mając to na uwadze, mimo że jest to złe rozwiązanie twojego problemu . Możesz używać samego basha, aby robić, co chcesz, jeśli masz naprawdę czyste dane bez znaków specjalnych, gdzie specjalne jest zdefiniowane jako wszystko spoza [A-Za-z0-9 ]:

$name":"john"}" $ # remove everything through the first "{" $ echo $id "name":"john"} $ # remove everything starting with the last "}" $ echo $id "name":"john" $ name="${id%:*}" # take everything before the ":" $ name="${name//\"/}" # remove quotes $ echo $name name $ value="${id#*:}" # take everything after the ":" $ value="${value//\"/}" # remove quotes $ echo $value john 

Wszystko to jest opisane w „Rozwijaniu parametrów” w podręczniku bash . Na przykład ${parameter#word}, co spowoduje Remove matching prefix pattern, usunie tekst word z początku $parameter. Podobnie % usuwa przyrostek. // zamienia wszystkie wystąpienia ciągu na wszystko, co nastąpi po nim (w przykładzie ${foo//\"/} powyżej, cudzysłowy (które muszą zostać zmienione, więc pojawiają się jako \") są zastępowane pustym ciągiem znaków). Musisz jednak wykonać każde podstawienie samodzielnie: nie możesz odciąć początku i końca łańcucha jednym poleceniem.

Prawdopodobnie zauważyłeś również, że trzeba zmienić znaczenie znaków specjalnych, takich jak }, { i ". Tak długo, jak pamiętasz, aby zrobić to dobrze, możesz napisać taki kod z łatwością, ale mimo tego, że jest on prosty, ma on tendencję do bycia kodem tylko do zapisu. za rok lub dwa, aby ponownie go użyć, spojrzysz na coś takiego jak #*\{} i pomyślisz sobie: WTF czy to w ogóle oznacza? i następnie skopiuj go na ślepo do nowego projektu, a kod ulegnie subtelnemu zepsuciu, ponieważ napotka znaki specjalne, których się nie spodziewałeś.

Powyższe przykłady nie powiodą się, jeśli pary nazwa-wartość zawierają znaki specjalne, takie jak nawiasy klamrowe, cudzysłowy, dwukropki lub prawdopodobnie inne znaki. Więc to zadziała dobrze w przypadku szybkiego i brudnego skrobania lub przypadku użycia 80%, ale naprawdę nie powinieneś używać go w produkcji ani za każdym razem, gdy musisz upewnić się, że zawsze działa z jakimkolwiek wejściem.

Nawet bez instrukcji echo, które pokazują, co się dzieje, możesz zobaczyć, że ten kod jest już dłuższy niż przykłady w innej odpowiedzi, które pokazują, jak to zrobić prawidłowo. Dlatego nie korzystając z narzędzia innej firmy, „dajesz sobie więcej kodu do napisania, co zajmie więcej czasu zarówno na pisanie, jak i debugowanie”. Otrzymujesz również rozwiązanie, które jest mniej elastyczne i przerywa, gdy napotyka coś nieoczekiwanego.

Komentarze

  • to było dość pouczające – czy ' t nie rozumieć, dlaczego ludzie mieliby głosować przeciw

Odpowiedz

Alternatywnie możesz użyć uniksa opartego na ścieżce narzędzie jtc :

id="{"name":"john"}" bash $ key=$(jtc -w"[0]<>k" <<<"$id") bash $ echo $key "name" bash $ value=$(jtc -w"[0]" <<<"$id") bash $ echo $value "john" bash $ 

PS> Ujawnienie: Jestem twórcą narzędzia jtc – powłoki CLI do operacji JSON

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *