JC, popüler komut satırı araçlarının çıktısını JSON’a dönüştürüyor
(github.com/kellyjonbrazil)- JC, çeşitli CLI araçlarının, dosya biçimlerinin ve düz metinlerin çıktısını JSON’a çevirerek betiklerde daha kolay ayrıştırılmasına yardımcı olan bir araçtır
- Pipe üzerinden girdi alıp
STDOUT’a JSON yazar; ayrıcajc dig example.comgibi komutun önüne eklenen magic syntax’ı da destekler - Varsayılan çıktı, parser’a özgü katı bir şema kullanır; sayıları,
nulldeğerlerini, boolean değerleri ve ek anlamsal alanları dönüştürür.-rveyaraw=Trueile ön işleme öncesi ham JSON’a erişilebilir - Python kütüphanesi olarak da kullanılabilir; JSON yerine Python sözlüğü, sözlük listesi veya lazy iterable biçiminde sonuç alınabilir
- Büyük hacimli ve uzun süre çalışan pipeline’lar için JSON Lines/NDJSON üreten streaming parser,
--slurp,--meta-out, yerel parser eklentileri ve platform uyumluluğu uyarılarını bastırma seçenekleri sunar
JC ne yapar
- JC(JSON Convert), çeşitli CLI araçlarının, dosya biçimlerinin ve düz metinlerin çıktısını JSON’a dönüştürür
- Dönüştürülen çıktı, ek işlem için
jqveyajellogibi araçlara pipe ile bağlanabilir - Örnekte
dig example.com | jc --dig,digçıktısını bir JSON dizisine dönüştürür; ardındanjq -r '.[].answer[].data'ile yalnızca IP adresleri çıkarılır - Aynı işlem
jc dig example.com | jq -r '.[].answer[].data'şeklinde magic syntax ile de çalıştırılabilir
CLI ve Python kütüphanesi kullanım biçimi
- Temel CLI kullanımı, pipe girdisini alıp JSON gösterimini yazdırma şeklindedir
COMMAND | jc [SLICE] [OPTIONS] PARSERcat FILE | jc [SLICE] [OPTIONS] PARSERecho STRING | jc [SLICE] [OPTIONS] PARSER
- magic syntax,
jc [SLICE] [OPTIONS] COMMANDveyajc [SLICE] [OPTIONS] /proc/<path-to-procfile>biçiminde komutun ya da/procdosyasının önünejcekler- Komut alias’ları ve shell builtin’leri desteklenmez
- Python’da
jc.parse('dig', cmd_output)şeklinde çağrılır- Dönüş değeri bir JSON string’i değil; Python sözlüğü, sözlük listesi veya streaming parser’ın lazy iterable’ı olabilir
- Python paket dokümantasyonu
help('jc'),help('jc.lib')veya çevrimiçi dokümanlar üzerinden görülebilir
Çıktı gösterimi ve şema
- Varsayılan gösterim, parser’a özgü katı bir şema kullanır
- Bilinen sayılar JSON
intveyafloatdeğerlerine dönüştürülür - Bilinen
Nonedeğerleri JSONnulldeğerine dönüştürülür - Bilinen boolean değerler de dönüştürülür
- Bazı parser’lar ek anlamsal alanlar ekler
- Bilinen sayılar JSON
- Ham ön işleme JSON’una CLI’daki
-rseçeneği veya Python kütüphanesindekiparse(..., raw=True)ile erişilir - Her parser’ın şeması, parser listesinin yanındaki dokümantasyon bağlantısından görülebilir
- JSON çıktısı varsayılan olarak compact biçimdedir;
-pseçeneğiyle pretty format kullanılabilir -yveya--yaml-outseçeneğiyle YAML çıktısı da mümkündür
Desteklenen parser’lar ve kullanım örnekleri
- Desteklenenler CLI komutları, dosya biçimleri ve string parser’larından oluşur
- README’deki parser listesinde
dig,ls,ping,ps,netstat,ifconfig,csv,xml,yaml,/etc/hosts,/etc/passwd,/proc/,systemctl,git log,jwt,url,semver,x509ile ilgili dosyalar ve benzerleri yer alır - Örnek çıktılar, çeşitli girdilerin JSON yapısına nasıl dönüştürüldüğünü gösterir
arpçıktısı adres, donanım tipi, MAC adresi ve arayüz alanlarına dönüştürülür- CSV dosyası, başlıkları anahtar olarak kullanan nesne dizisine dönüştürülür
/etc/hosts, IP ve hostname dizilerine dönüştürülürifconfig, arayüz adı, MTU, IPv4/IPv6 adresleri, paket ve bayt sayaçları gibi bilgileri içeren nesnelere dönüştürülürping, gönderilen/alınan paket sayısı, kayıp oranı, gidiş-dönüş süresi ve yanıt listesini içeren bir nesneye dönüştürülür
- Ansible’da
community.generalkoleksiyonunun filter plugin’i olarak kullanılabilir
Kurulum yöntemi
jcbirkaç farklı yöntemle kurulabilirpip3 install jc- OS paket depoları
- GitHub Releases’teki mimariye göre hazırlanmış ikili dosyalar
- OS paketiyle kurulum örnekleri şunları içerir
- Debian/Ubuntu:
apt-get install jc - Fedora:
dnf install jc - openSUSE:
zypper install jc - Arch:
pacman -S jc - macOS:
brew install jc - FreeBSD: ports üzerinden kurulum
- Ansible filter plugin:
ansible-galaxy collection install community.general - FortiSOAR connector: FortiSOAR Connector Marketplace’ten kurulum
- Debian/Ubuntu:
Başlıca seçenekler
-a/--about:jcve parser bilgilerini JSON veya YAML olarak yazdırır-d/--debug: Ayrıştırma sorunu olduğunda izleme mesajları yazdırır;-dddaha ayrıntılı hata ayıklama sağlar-h/--help: Yardımı yazdırır;jc -h --parser_nameile parser dokümantasyonu görülebilir-M/--meta-out: Zaman damgası, parser adı, magic command, magic command exit code gibi metadata bilgilerini çıktıya ekler-q/--quiet: Parser uyarı mesajlarını bastırır;-qqstreaming parser hatalarını yok sayar-s/--slurp: Çok satırlı girdiyi bir diziye toplar-u/--unbuffer: Çıktı buffering’ini devre dışı bırakır-B/--bash-comp,-Z/--zsh-comp: Bash veya Zsh completion script’i üretir
Slice ve Slurp
- Slice, Python slicing’e benzer
START:STOPsöz dizimiyle yalnızca girdi satırlarının bir bölümünü işler - Örneğin başlığı ve alt bilgisi olan bir tabloda,
jc 1:-1 --asciitableveyajc 1:4 --asciitableile ortadaki veriler JSON’a dönüştürülebilir - Pozitif ve boş slice en iyi bellek verimliliğini sağlar; negatif slice daha fazla bellek kullanır
- Slurp, tek satırlık girdi alan string parser’larında birden fazla öğeyi tek seferde dizi olarak yazdıran bir özelliktir
- Örn: Her satırda bir IP adresi bulunan bir dosya
jc --slurp --ip-addressile işlenir
- Örn: Her satırda bir IP adresi bulunan bir dosya
/procmagic syntax, birden fazla dosya seçildiğinde slurp’ü otomatik olarak destekler- Birden fazla
/procdosyası dönüştürüldüğünde, her sonuç nesnesinin hangi dosyaya karşılık geldiğini göstermek için_filealanı eklenir
- Birden fazla
--meta-outslurp ile birlikte kullanıldığında,resultdizisi ve_jc_metanesnesiyle sarmalanmış bir yapı yazdırılır
Çıkış kodu ve metadata
jciçindeki ölümcül hatalar çıkış kodu100üretir; aksi halde0döndürür- Magic syntax kullanıldığında
jc, ayrıştırılacak programın çıkış kodunu saklar ve bunujcçıkış koduna eklerifconfig1,jc0ise birleşik çıkış kodu1olurifconfig0,jc100ise birleşik çıkış kodu100olur- İkisinde de hata varsa birleşik çıkış kodu
101olur
- Magic syntax’ta
--meta-outveya-Mkullanıldığında_jc_metanesnesi magic command bilgilerini ve çıkış kodunu içerir
Renkler ve ortam değişkenleri
JC_COLORSortam değişkeniyle key name, keyword, number ve string renkleri belirtilebilir- Biçim
JC_COLORS=<keyname_color>,<keyword_color>,<number_color>,<string_color>şeklindedir - Renk değeri
black,red,green,yellow,blue,magenta,cyan,gray,brightblack,brightred,brightgreen,brightyellow,brightblue,brightmagenta,brightcyan,white,defaultseçeneklerinden biri olabilir
- Biçim
NO_COLORortam değişkeni ayarlanırsa renkli çıktı devre dışı bırakılır-Cseçeneği,NO_COLORortam değişkeni ve-mseçeneğinin önüne geçerek renkli çıktıyı zorunlu kılar
Streaming parser
- Çoğu parser,
STDIN’in tamamını belleğe okuyup ayrıştırdıktan sonra JSON belgesini seri halde yazar - Bazı streaming parser’lar girdiyi alır almaz satır satır işler ve JSON Lines veya NDJSON olarak yazdırır
- Örn:
ls-s,ping-s ls -lR /gibi büyük komut çıktılarında bellek kullanımını ciddi ölçüde azaltabilir ve bazı durumlarda daha hızlı işleyebilir
- Örn:
- Streaming parser’lar magic syntax ile birlikte kullanılamaz
- Uzun süre çalışan pipeline’larda ayrıştırma hatasının pipe’ı bozmaması için
-qqveya Python’dakiignore_exceptions=Truekullanılabilir- Başarılı satırlar
_jc_meta.success: trueiçerir - Başarısız satırlar
_jc_meta.success: false,error,linealanlarını içerir
- Başarılı satırlar
- Pipe’lar arasında işletim sistemi buffer’ı nedeniyle çıktı gecikmeli görünüyorsa
-uile unbuffered output kullanılabilir- Ancak büyük veri akışlarında unbuffered output daha yavaş olabilir
- Python’da streaming parser’lar iterable girdi alır ve lazy işlem için iterable nesne döndürür
Parser eklentisi
- Yerel parser plugin’i, uygulama veri dizinindeki
jc/jcparsersklasörüne konabilir- Linux/unix:
$HOME/.local/share/jc/jcparsers - macOS:
$HOME/Library/Application Support/jc/jcparsers - Windows:
$LOCALAPPDATA\jc\jc\jcparsers
- Linux/unix:
- Eklentiler standart Python modül dosyalarıdır
jc/parsers/foo.pyveyajc/parsers/foo_s.pyşablon olarak kullanılabilir- Eklenti dosya adı geçerli bir Python modül adı olmalı; harfle başlamalı ve yalnızca alfanümerik karakterler ile underscore içermelidir
- Yerel eklentiler varsayılan parser’ları override edebilir
Locale, saat dilimi ve uyumluluk
- En iyi sonuçlar için
LC_ALLdeğerininCveyaen_US.UTF-8olarak ayarlanması önerilir - Bazı eski sistemlerde
Clocale’i UTF-8 kodlamasını desteklemediğinden UTF-8 çıktı ASCII ve\\uescape sequence’larına düşebilir - Bazı parser’lar hesaplanmış epoch timestamp alanları ekler
- Alan adı
_utcsuffix’ine sahip değilse yerel saat dilimine dayalı naive timestamp kabul edilir - UTC saat dilimi komut çıktı metninde algılanırsa timezone aware timestamp olur ve anahtar adına
_utcsuffix’i eklenir - UTC dışındaki saat dilimleri aware timestamp olarak desteklenmez
- Alan adı
- Bazı parser’lar platforma özgü çıktıları dönüştürdüğünden desteklenmeyen bir platformda çalıştırıldığında uyarı yazdırır
- Desteklenmeyen platformlarda da başka sistemlerin çıktı dosyaları ayrıştırılabilir; bu durumda
-qveya Python’dakiquiet=Trueile uyarılar bastırılabilir - Test edilen platformlar arasında Centos 7.7, Ubuntu 18.04/20.04, Fedora32, macOS 10.11.6/10.14.6, NixOS, FreeBSD12, Windows 10, Windows 2016 Server ve Windows 2019 Server yer alır
1 yorum
Hacker News yorumları
FreeBSD’de bu sorun libxo ile bir ölçüde çözülmüş durumda:
$ ps --libxo=json | jqgibi yapılandırılmış çıktı alınabiliyorKusursuz değil;
lsdesteği vardı ama bir nedenle kaldırıldı ve tüm yardımcı araçlar da desteklemiyorjc, birçok komut ayrıştırıcısı sunan iyi bir geçici çözüm gibi görünüyor; ancak en baştan ayrıştırma için tasarlanmamış metin çıktısını ayrıştırma sınırlamasına sahipYardımcı araçların ortak bir bayrakla yapılandırılmış çıktı üretmesi için birleşmesi iyi olurdu; PowerShell’deki gibi varsayılan olması Unix/Linux için fazla olsa da standart bir
--jsonbayrağı bile büyük bir ilerleme olurhttps://wiki.freebsd.org/LibXo
https://reviews.freebsd.org/D13959
Anladığım kadarıyla yalnızca yapılandırılmış veri geçirmekle kalmıyor; opak nesneleri pipeline’dan geçirip önceki adıma dönerek metot da çağırabiliyor: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_methods?view=powershell-7.4
jc,libxogibi wrapper’ları ve https://www.nushell.sh/ gibi deneysel shell’leri de seviyorum; ancak bunlar çalıştırılabilir metotları olan nesnelerden çok veri aktarımına odaklanıyorYapılandırılmış veri hâlâ Unix’e uygun hissettiriyor; gerçek nesnelere ihtiyaç varsa Python ya da Ruby açma zamanı geldiğini düşünüyorum
Shell ne kadar iyi olursa olsun ve programlama özellikleri ne kadar güçlü olursa olsun, ne zaman shell betiğinden ciddi bir programlama diline geçileceğini bilmek önemli
jcbu zamana kadar bu rolü dolduran bir araç olarak tanıtılıyor ve Unix araçlarının genelinde-j/--jsondesteği yaygınlaşana kadar bir basamak taşı olarak amaçlandığı anlaşılıyorhttps://blog.kellybrazil.com/2019/11/26/bringing-the-unix-philosophy-to-the-21st-century/
/procaltındaki öğeler yapılandırılmamış metin dosyaları yerine JSON verisi döndürüyorDaha yapısal bir çözüm, ELF içinden veri yapılarını dışa aktarılabilir kılmak; bu veri yapılarını terminal çıktısına serileştirdikten sonra kullanıcının istediği JSON, YAML gibi biçimlerde çıktı almasına ya da işlemesine izin vermek olabilir
Tam olarak hangi yardımcı araç olduğunu hatırlamıyorum ama muhtemelen
iostatidi; JSON çıktı satırlarını string interpolation ile biçimlendirirken belirli bayrak kombinasyonlarında tamamen bozuk çıktı üretiyorduŞimdi düzelip düzelmediğini bilmiyorum ama aralık seçeneği varken JSON lines benzeri bir biçim beklerdim
Kullanılabilirlik açısından PowerShell ve kubectl’in libxo’dan çok daha ileride olduğunu düşünüyorum
https://github.com/Juniper/libxo
https://libxo.readthedocs.io/en/latest/
Fikir gerçekten çok iyi, ama bakımını düşününce insan huzursuz oluyor
Sürüm ve komut bayraklarına göre çıktı değişiklikleri gibi şeyler hesaba katılınca bakım cehennemi gibi görünüyor; pratikte bazı durumlarda iyi çalışacaktır ama temel örneklerin ötesine geçince yenilik hissi hızla kaybolacak gibi
Ayrıca araç seçeneklerinde
--kullanmak da pek iyi görünmüyorHer yeni ayrıştırıcı için yeni bir bayrak gerekiyorsa yardım ya da kılavuz sayfaları binlerce satıra ulaşabilir
Bir yardımcı araç kendi JSON dışa aktarımını desteklemeye karar verdiğinde, bundan sonra bu araç o özelliğe delege edebilir
jc lsgibi komutun başınajcekleyerek de kullanılabildiği görülüyor--cmdparametresi, dönüştürme öncesinde veriyi işlemeyi mümkün kıldığı için aslında iyi bir fikirÖrneğin dönüştürmeden önce listeyi
greplemek isteyebilirsinizBakım açısından da temel Unix komutlarının çıktısı büyük ölçüde değişirse yalnızca bu aracı değil, sayısız betiği de bozacağından; başka ikili dosya güncellemeleri yüzünden sanıldığı kadar sık bozulacak gibi görünmüyor
İyi yönetilen tek bir ortak ayrıştırıcı paketi, oraya buraya dağılmış geçici çıktı ayrıştırıcılarından daha iyidir; ancak karmaşık işler yapmaya çalışıp doğrudan JSON çıktısına ihtiyaç duyduğum durumlarda ayrıştırmanın kendisinin soruna ek yük getirmemesini isterim
Bunu rahat kullanmak için, sanırım kullanacağım her şey için ek test vakalarını PR olarak göndermek gerekir
Zaten o testleri kendim yazmak zorunda kalacaktım
İnsanların ihtiyaç duyulan araçların ayrıştırma bilgilerini göndermesi ve kullananların bunları kolayca güncel tutması dışında yol yok
Nushell’in yaklaşımı farklı olsa da çoğunlukla aynı noktaya, kabuk komutlarının yapılandırılmış verisine ulaşıyor
Bu rolü esas olarak kabuğun kendisinin üstlendiği bir yaklaşım
http://www.nushell.sh/
from jsonişlemi var; bu yüzden JC ile gerçekten iyi uyum sağlıyorDaha önce Nushell’in bazı güzel özelliklerini gösteren bir video kaydetmiştim; 19. dakika civarında
jcile birlikte kullanmaktan bahsediyorum: https://www.youtube.com/watch?v=KF5dtxVsn1EBelirli bir desene uyan dizinlerdeki dosyaları tarayıp, değiştirilme zamanları birbirinden 10 dakika içinde olanları kaldıran bir script yazmaya çalışırken Nushell’in böyle işler için iyi olduğunu hatırladım
Biraz kurcalayınca sonunda kafama yattı ve şimdi ona kapılmış durumdayım
Yapılandırılmamış veriyi bile kayıt listesi gibi bir biçime dönüştürüp işleyebiliyorsanız bu çok güçlü
Bir anlamda dosyaların her yerde olması harika; Unix’in vaadi bu, Plan 9’da da daha genişletilmiş hali
Ama yapılandırılmamış dosyalar ya da her dosyanın kendi formatına sahip olması da aynı ölçüde ayak bağı oluyor
Yalnızca
awkgibi araçlarla tek bir nginx günlük dosyasını ayrıştırmaya çalışmak bile zahmetli olabilirBüyük eksilerden biri, Linux kullanıcı alanında büyük ölçekli sistem yeniden yazımlarını ya da tasarım değişikliklerini hayata geçirmenin zor olması
Daha akıllı bir kabuk istiyorum, dosyaları da seviyorum, yanımda
awkkitabı da duruyor; ama artık veri ayrıştırma konusunda ciddi bir iyileştirme zamanının geldiğini düşünüyorumProgramların renkli çıktı render edip etmeyeceğine kendilerince karar vermesi gibi, yapılandırılmış çıktı verip vermeyeceğini de yapabilmesi iyi olurdu
Herhangi bir metin arayüzü API gibi kullanılabildiği için insanın okuması kolay metin öncelik kazanıyor
Bu yüzden kabuk betikleme, üçüncü taraf tarayıcı eklentisi yazmaya benziyor
Bakıp tahmin ediyor, sonra o tahmine dayanarak aceleyle bir ayrıştırıcı uyduruyor ve çalışmasını umuyorsunuz
Makinenin okuyacağı içerik için üçüncü bir standart çıktı olsa iyi olurdu
Terminal varsayılan olarak bunu basmaz, pipe yapıldığında bu çıktı pipe edilir, JSONL olur ve man sayfası sözleşmeyi belirtir
Böylece standart çıktı insanlara ayrılmış kalabilir; ayrıştırma ise mümkün ama kırılgan olduğunu bilerek yapılan bir iş olur
Elbette bu tamamen geriye dönük uyumluluğu bozan bir fikir; gerçekçi olmayan biçimde CLI’ı temelden yeniden icat edip modernleştirecek olsak değiştirmek isteyeceğim şeylerin listesi uzun
İyileştirme elde etmek de gerçekten zor; Lennart gibi biri onlarca yıllık eski tortuları temizlemeye kalkınca hemen drama çıkıyor
JSON da hâlâ kusursuz değil
JSON fena sayılmayan bir fikir, ama işi doğru yapmak için veri türleri gibi şeyleri ifade edebilen bir biçime ihtiyaç var
Sayıları sayı olarak ele alıp
$a - $bile tarih farkı hesaplama gibi şaşırtıcı şeyleri yapabilmek için PowerShell’e daha yakın bir yaklaşım gerekirBunun GNU coreutils’te gerçekleşmesini isterdim
Sorun, .NET’e ve nesnelere fazlasıyla kök salmış olması; bu yüzden herhangi bir platformda mevcut yerel komutlarla bütünleştirmek çok zor
Çünkü özünde zaten aynı işi yapıyorlar
Yine de nihai hedef muhtemelen üst seviye araçların değeri görüp doğrudan yapılandırılmış çıktı sunması olacak
Harika
Makul JSON çıktısını destekleyen CLI araçlarını güçlü biçimde destekliyorum; https://github.com/WireGuard/wireguard-tools/blob/master/contrib/json/wg-json gibi şeyler ve PowerShell’in
|ConvertTo-Jsonözelliği yönetim/izleme otomasyonunun büyük bir parçasıAncak burada makul kelimesi çok iş yapıyor ve gerçekler de ortada
LSI/Broadcom StorCLI’de komutun sonuna
Jekleme yöntemi ya da PowerShell’in COM’u gizleyen wrapper’ları gibi, teknik olarak JSON olan ama sonucu saçma derecede karmaşık veya kullanışsız çıkan şeyler yüzünden çoğu zaman sonunda “düz metin çıktıya biraz regex uygulayalım” geçici çözümüne geri dönülüyorYine de buna mutlaka bakacağım
İlk örnek olan
digçıktısını ayrıştırma, güvenilir biçimde yapılabilecek işleri temsil ediyorsa epey ilginç olabilirBence varsayılan sözdizimi
jc dig example.comolmalıÇünkü
dig example.com | jc --dig, çıktıyı ayrıştırmak için önceki komutun bayraklarını ve parametrelerini sonradan tahmin etmeyi gerektiriyorTüm çıktıların nesne olması, PowerShell’de en sevdiğim şeylerden biri
Ne zaman bash scripti yazmak zorunda kalsam bunu özlüyorum
Bunu bakımını üstlenmeye karar veren kişiye saygılar
aws s3 ls | jc --aws=1.2.3gibi bir şeyse kâbus olurLinux veya Unix’teki
fileprogramını ve onun bakımını yapan kahramanları hatırlatıyorpluginsgibi şeyler yüklenebiliyorsa, örneğin ayrı kabuk komutu biçiminde tutarak bakım emeğinin bir kısmını eklenti yazarlarına devredebilirsiniz--jsonseçeneğini kabul eden modern Unix komut satırı araçlarının bir listesinin olup olmadığını merak ediyorumBu depoya böyle bilgileri eklemek de faydalı olabilir
ifconfig’in modern alternatifi olanipJSON’u destekliyorlldpctlde destekliyorAnsible, sistem ayrıntılarını
factsadlı JSON olarak sunuyor ve otomasyonun bunlardan yararlanması için tasarlanmışlsblk,--jsonbayrağını kabul ediyor ve çok fazla bilgi verebiliyorlsblk --json --output-allkomutunu deneyebilirsinizBir betiğin sistemdeki diskleri ve bölümleri kontrol etmesi gerektiğinde çok kullanışlı
-T jsonbayrağıyla destekliyorİlginç bir proje
Ama ilk aşama ayrıştırıcı olarak textfsm gibi bir şey kullanacağını düşünmüştüm
textfsm, ağ cihazlarının CLI çıktısını ayrıştırmak için yaygın olarak kullanılıyor
https://github.com/google/textfsm