Analizați un șir în scriptul bash

Am analizat alte răspunsuri, dar nu am putut obține o explicație corectă despre cum să faceți acest lucru.

I au o variabilă de șir numită id astfel încât id="{"name":"john"}". Cum pot obține 2 variabile din acest șir ca-

key="name" value="john" 

O explicație detaliată ar fi apreciată deoarece vreau să înțeleg analiza șirurilor în bash.

Până acum, am „eliminat parantezele {} din șirul de caractere-

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

Nu pot” include " acolo ca generează o eroare. De asemenea, căutați ceva de genul id.split(":") în cele din urmă pentru a obține o matrice.

Comentarii

  • Vă putem avertiza cu privire la această tactică / pistă înainte ca ‘ să fie prea târziu? Se pare că aveți json sau alte date structurate acolo; poate ar fi un instrument dedicat o modalitate mai sigură de a vă duce acolo unde vă aflați mergeți?
  • Am văzut că jq este folosit de alții, dar nu există nicio modalitate de a putea analiza acest lucru fără un terț instrument?
  • Aduceți aceste date dintr-un fișier? Ar putea exista mai multe perechi de chei / valori? Cum ar arăta un ghilimel ca parte a valorii?
  • @kev: Tehnic awk, sed și grep sunt, de asemenea, instrumente terță parte. Dacă utilizați date json, nu există absolut niciun motiv să nu aveți instrumentele adecvate pentru a lucra cu acestea.
  • Aceste date sunt rezultatul unei comenzi pe care executat în scriptul meu. Va fi întotdeauna în acest format – 1 cheie și 1 valoare.

Răspuns

Utilizarea jq:

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

-r: Cu această opțiune, dacă filtrul „s rezultatul este un șir, apoi va fi scris direct la ieșirea standard, mai degrabă decât formatat ca un șir JSON cu ghilimele.

keys: Tastele funcționale încorporate, când dat unui obiect, își returnează cheile într-o matrice.


Utilizând json:

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

-a procesează intrarea ca matrice

-k returnează valorile cheie

Comentarii

  • vă mulțumesc pentru explicație. Funcționează excelent. Cred că nu există ‘ că nu există nicio modalitate de a analiza un șir fără jq în scripturile bash.
  • @kev: Există o mulțime de moduri de a analiza șirurile, dar este ‘ un fel de nedrept pentru a numi asta un șir și nu date JSON.
  • @kev Datele JSON pot fi codate. Pentru a-l analiza, ar trebui să-l decodezi. De asemenea, JSON nu-i pasă de spațiile albe (linii noi etc.) între taste și valori, așa că ar trebui să țineți cont de asta. Acest lucru a fost făcut deja pentru dvs. de către autorii analizorului JSON subiacent din jq.

Răspuns

Ați cerut literalmente să understand string parsing in bash așa că voi scrie un răspuns având în vedere acest lucru, chiar dacă este soluție greșită pentru problema dvs. . Puteți folosi bash în sine pentru a face ceea ce doriți, dacă aveți cu adevărat curat date fără caractere speciale, în care special este definit ca orice în afara [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 

Toate acestea sunt descrise în „Extinderea parametrilor” în manual bash . De exemplu, ${parameter#word} care va Remove matching prefix pattern va elimina textul word de la începutul lui $parameter. În mod similar, % elimină sufixul. // înlocuiește toate aparițiile unui șir cu orice vine după el (în exemplul ${foo//\"/} de mai sus, ghilimele (care trebuie să fie evitate, deci apar ca \") sunt înlocuite cu șirul gol). Totuși, trebuie să efectuați fiecare înlocuire de la sine: nu puteți „elimina începutul și sfârșitul șirului cu o singură comandă.

De asemenea, ați observat probabil trebuie să scape de caractere speciale, cum ar fi }, { și ". Atâta timp cât vă amintiți să faceți acest lucru corect, puteți scrie codul astfel destul de ușor, dar, oricât de simplu este, este în tendință să fie cod numai pentru scriere. Când reveniți cod într-un an sau doi pentru a-l reutiliza, veți privi ceva de genul #*\{} și vă veți gândi, WTF înseamnă chiar asta? și apoi doar copiați-l orbește într-un proiect nou și apoi codul dvs. se va sparge într-un mod subtil, deoarece întâlnește caractere speciale pe care nu vă așteptați.

Exemplele de mai sus se vor sparge dacă perechile dvs. nume-valoare au caractere speciale în ele, cum ar fi paranteze sau ghilimele sau două puncte sau probabil alte caractere. Deci, acest lucru va funcționa bine pentru o răzuire rapidă și murdară sau pentru cazul de utilizare de 80%, dar nu ar trebui să-l folosiți în producție sau în orice moment trebuie să vă asigurați că funcționează întotdeauna cu orice intrare.

Chiar și fără declarațiile echo de acolo pentru a vă arăta ce se întâmplă, puteți vedea că acest cod este deja mai lung decât exemplele din celălalt răspuns care arată cum să o faceți corect. Deci, dacă nu utilizați un instrument terță parte, vă „dați mai mult cod pentru a scrie, ceea ce vă va duce mai mult la scriere și depanare, și veți de asemenea să ajungeți la o soluție care este mai puțin flexibilă și care va pauză când întâmpină ceva neașteptat.

Comentarii

  • acest lucru a fost destul de informativ – poate ‘ nu înțelegeți de ce oamenii ar vota negativ

Răspuns

Alternativ, puteți utiliza un unix bazat pe o cale de mers pe jos utilitar 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> Divulgare: sunt „creatorul instrumentului jtc – instrumentul shell cli pentru operațiuni JSON

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *