Json metnini ayrıştırmak için sed komutuyla normal ifade


15

Bu json metni var:

{
    "buildStatus" : {
        "status" : "ERROR",
        "conditions" : [{
                "status" : "OK",
                "metricKey" : "bugs"
            }, {
                "status" : "ERROR",
                "metricKey" : "test_success_density"
            }, {
                "status" : "OK",
                "metricKey" : "vulnerabilities"
            }
        ],
        "periods" : []
    }
}

Ben buildStatus genel durumunu ayıklamak istiyorum, yani beklenen çıktı "HATA" oldu

"buildStatus" : {
    "status" : "ERROR",
    ....
}

Aşağıdaki sed ifadesini denedim, ancak çalışmıyor, döndürür OK:

status= sed -E 's/.*\"buildStatus\":.*\"status\":\"([^\"]*)\",.*/\1/' jsonfile

Neyi yanlış yapıyorum?

Yanıtlar:


16

Normal ifadelerle JSON veya XML gibi karmaşık iç içe veri yapılarını ayrıştırmayın, gibi uygun bir JSON ayrıştırıcı kullanın jshon.

İlk önce yüklemeniz gerekir:

sudo apt-get install jshon

Ardından, standart giriş yoluyla ayrıştırmak için JSON verilerini sağlamanız gerekir, böylece başka bir komutun çıktısını bir pipe ( |) ile yönlendirebilir veya bir dosyayı ona ( < filename) yönlendirebilirsiniz .

İstediğiniz verileri ayıklamak için gereken argümanlar şöyle görünür:

jshon -e "buildStatus" -e "status" -u
  • -e "buildStatus" üst düzey sözlükten "buildStatus" dizinine sahip öğeyi seçer.
  • -e "status" yukarıda seçilen ikinci düzey sözlükten "status" dizinine sahip öğeyi seçer.
  • -u Seçilen verileri JSON'dan düz verilere dönüştürür (yani burada dizenin etrafındaki tırnak işaretlerini kaldırır)

Dolayısıyla, verileri nereden aldığınıza bağlı olarak çalıştırdığınız komut bunlardan birine benziyor:

jshon -e "buildStatus" -e "status" -u < YOUR_INPUT_FILE
YOUR_JSON_PRODUCING_COMMAND | jshon -e "buildStatus" -e "status" -u

Hakkında daha fazla bilgi edinmek için jshon, buradan veya yalnızca yazarak erişebileceğiniz çevrimiçi sayfasını okuyabilirsiniz man jshon.


6
Ayrıca jq:jq -r .buildStatus.status
muru


(Soru soran budur) "Tek bir XML açık etiket" Çünkü @HTNW Ben bunun cevabını hiç sevmedim olan düzenli dil (ve prensip yapı içinde Regexes kullanarak bir tam XML ayrıştırıcı etiketleri, yorum, cdata maç için olabilir bölümleri ve iç içe bağlamı işlemek için basit bir yığın kullanma). Ancak, JSON'daki en 'ilginç' normal dil bir dizgi değişmezidir.
Random832

10

İş için jq:

jq -r '.["buildStatus"]["status"]' file.json

Kısaltılabilir:

jq -r '.buildStatus.status' file.json

-r( --raw-output), dizeyi jsondize biçimlendirmesi olmadan, yani tırnak işaretleri olmadan çıkarır.

Misal:

% cat file.json                   
{
    "buildStatus" : {
        "status" : "ERROR",
        "conditions" : [{
                "status" : "OK",
                "metricKey" : "bugs"
            }, {
                "status" : "ERROR",
                "metricKey" : "test_success_density"
            }, {
                "status" : "OK",
                "metricKey" : "vulnerabilities"
            }
        ],
        "periods" : []
    }
}

% jq -r '.["buildStatus"]["status"]' file.json
ERROR

% jq -r '.buildStatus.status' file.json       
ERROR

Zaten kurulmadıysa, yükleyin (Evren deposunda bulunur):

sudo apt-get install jq 

8

Daha önce de belirtildiği gibi, karmaşık yapılandırılmış verilerin ayrıştırılması uygun API ile tercih edilir. Python bunun için jsonmodül içeriyor, ki ben kişisel olarak benim scriptlerimde çok kullanıyorum ve istediğiniz alanları istediğiniz gibi ayıklamak oldukça kolay:

$ python -c 'import sys,json;print json.load(sys.stdin)["buildStatus"]["status"]' <  input.txt
ERROR

Burada olan şey, girdi dosyasını python's stdin'e yönlendiriyor ve bunu ile okuyoruz json.load(). Bu, "buildStatus" anahtarıyla bir python sözlüğü olur ve "status" anahtarıyla başka bir python sözlüğü içerir. Böylece, sadece bir sözlükte başka bir sözlükte saklanan bir anahtarın değerini yazdırıyoruz. Oldukça basit.

Basitliğin yanı sıra, bir başka avantaj da python ve bu API'nin önceden kurulu olması ve varsayılan olarak Ubuntu ile birlikte gelmesidir.


6

Sen olabilir aslında bu in yapmak sed, ama güçlü JSON verilerini işlemek için yazılı araçlara sahiptir daha sofistike bir dil kullanmaya çağırıyorum. Örneğin perl veya python'u deneyebilirsiniz.

Şimdi, basit örneğinizde, istediğiniz tek şey ilk ortaya çıkmasıdır "status", böylece şunları yapabilirsiniz:

$ sed -nE '/status/{s/.*:\s*"(.*)",/\1/p;q}' file.json 
ERROR

Hüner kullanmaktır -nönlemek baskı, sonra hat maçlar ise status( /status/), her şeyi kaldırmak ama istediğiniz bölümü s/.*:\s*"(.*)",/\1/, pçizgi ve Rint quit.


Şahsen, bu eşdeğer grep komutunu çok daha basit buluyorum:

$ grep -m1 -oP '"status"\s*:\s*"\K[^"]+' file.json 
ERROR

Ya da bu:

$ perl -ne 'if(s/.*"status"\s*:\s*"([^"]+).*/$1/){print;exit}' file.json 
ERROR

Cidden, JSON dosyalarını ayrıştırmayı planlıyorsanız, bunu manuel olarak yapmaya çalışmayın. Uygun bir JSON ayrıştırıcı kullanın.


ya da bu:grep -m 1 status file.json | tr -cd '[[:alnum:]]:' | cut -f2 -d':'
slowko

1
@ user1876040 rica ederim. Lütfen cevaplardan birini kabul etmeyi unutmayın ( ByteCommander'ın tavsiye ederim , daha iyi bir çözümdür), böylece soru cevaplanmış olarak işaretlenebilir).
terdon

6

Eğer söylemiyorum gerektiğini kullanmak sedsize bir şey aramak gerekiyorsa, ama (birisi zorunlu uyarı yazmamak için beni downvoted düşünüyorum) sonraki hat buildStatus, sen söylemelisin kendi girişim çalışıyor gibi göründüğün kadar sedokumak Nkomutla sonraki satır

$ sed -rn '/buildStatus/N;s/.*buildStatus.*\n.*: "(.*)",/\1/p' file
ERROR

Notlar:

  • -n biz isteyene kadar hiçbir şey basma
  • -rERE kullan (ile aynı -E)
  • /buildStatus/N bu kalıbı bul ve sonraki satırı da oku
  • s/old/new/yerine oldsahipnew
  • .* satırdaki herhangi bir sayıda karakter
  • \n Yeni hat
  • : "(.*)",: "ve arasında oluşan karakterleri kaydet",
  • \1 kaydedilen desene geri başvuru
  • p üzerinde çalıştığımız kısmı yazdır

0

sedJSON ve XML gibi yapılandırılmış verileri ayrıştırmak için neden ve benzer metin akışı işleme araçlarının iyi donanımlı olmadığının tipik bir açıklaması vardır . Elimde yok, ama orada, ve özellikle yapıyı ayrıştırmak için inşa edilen alternatif araçların daha karmaşık olmasına rağmen, muhtemelen en az durumun hepsinde ihtiyaç duyulan ifadelerin hızla çok karmaşık hale geldiğine inanıyorum. zarif, okunabilir ve aynı ayrıştırmada verimli.

Gibi muru koydu yorumunda , jqiş için doğru bir araç olmalıdır. Ben de hemen hemen hiç yok ya da yükü başarı için aynı verileri ayrıştırma denedim birkaç kez yerini görmek için kişisel olarak çok heyecanlı olduğunu kefil olabilir. Hatta çıktıyı biçimlendirmek ve başka şekilde kontrol etmek için büyük bir kapasite içerir. Bunu jsontoolşu anda unuttuğum bir veya daha fazla nedenden dolayı tercih ediyorum .

Bayt Komutanı tavsiye görünüyor jshoniçinde başka bir yanıt . Bu aracı kullanmadım, ancak xmlstarletçıktı için bazı özelleştirilebilir sunum ile bana ve sözdizimini hatırlatıyor .



3
jsontoolOP'nin özel vakası için nasıl kullanılabileceğinin bir örneğini göstererek cevabınızı geliştirmeyi düşünün
Sergiy Kolodyazhnyy

Lol @muru, doğru, Regex ile XML / JSON ayrıştırma kullanımlarını caydırmaya çalışan mesajlardan biri! Daha tavsiyedir jqo Muru ve heemayl zaten exmaples olduğunu açıklayan ve hemen arkasında akıl gönderme: askubuntu.com/a/863948/230721
Pysis

0

Json adlı başka bir Json aracı ( https://github.com/trentm/json )

$ json buildStatus.status < file.json
ERROR

Bu örnek olay yanıltıcıdır: araçlar çalışmıyor gibi görünüyor. jsonJson dosyalarını değiştirmek için de kullanabilirsiniz :

$ json -e 'this.buildStatus.status="not error"' < file.json > new.json

ya da...

$ json -e 'this.buildStatus.status="no errors"' < file.json | json -e 'this.buildStatus.status
no errors

içindeki belgeler: http://trentm.com/json/


kurulu değilse:

  • düğümü kur
  • ve sudo npm install -g json
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.