JC แปลงเอาต์พุตของเครื่องมือคอมมานด์ไลน์ยอดนิยมเป็น JSON
(github.com/kellyjonbrazil)- JC เป็นเครื่องมือที่ช่วยแปลงเอาต์พุตจากเครื่องมือ CLI หลายชนิด, รูปแบบไฟล์ และสตริงทั่วไป ให้เป็น JSON เพื่อให้สคริปต์พาร์สได้ง่ายขึ้น
- รับอินพุตจาก pipe แล้วส่ง JSON ออกทาง
STDOUTและยังรองรับ magic syntax ที่วางไว้หน้าคำสั่ง เช่นjc dig example.com - เอาต์พุตเริ่มต้นใช้ schema แบบเข้มงวด แยกตาม parser และจะแปลงตัวเลข,
null, boolean รวมถึงฟิลด์เชิงความหมายเพิ่มเติม โดยสามารถเข้าถึง JSON ดิบก่อนการประมวลผลล่วงหน้าได้ด้วย-rหรือraw=True - ใช้เป็นไลบรารี Python ได้ด้วย โดยรับผลลัพธ์เป็น Python dictionary, รายการของ dictionary หรือ lazy iterable แทน JSON ได้
- สำหรับ pipeline ขนาดใหญ่หรือรันระยะยาว มี streaming parser ที่ส่งออก JSON Lines/NDJSON,
--slurp,--meta-out, plugin parser ภายในเครื่อง และตัวเลือกปิดคำเตือนเรื่องความเข้ากันได้ของแพลตฟอร์ม
JC ทำอะไร
- JC(JSON Convert) แปลงเอาต์พุตจากเครื่องมือ CLI หลายชนิด, รูปแบบไฟล์ และสตริงทั่วไป ให้เป็น JSON
- เอาต์พุตที่แปลงแล้วสามารถ pipe ต่อไปยังเครื่องมืออย่าง
jqหรือjelloเพื่อประมวลผลเพิ่มเติมได้ - ตัวอย่างคือ
dig example.com | jc --digเพื่อแปลงเอาต์พุตของdigเป็น JSON array จากนั้นใช้jq -r '.[].answer[].data'เพื่อดึงเฉพาะที่อยู่ IP - งานเดียวกันสามารถรันด้วย magic syntax ได้เช่นกัน เช่น
jc dig example.com | jq -r '.[].answer[].data'
วิธีใช้งาน CLI และไลบรารี Python
- การใช้งาน CLI พื้นฐานเป็นรูปแบบรับอินพุตจาก pipe แล้วส่งออก representation แบบ JSON
COMMAND | jc [SLICE] [OPTIONS] PARSERcat FILE | jc [SLICE] [OPTIONS] PARSERecho STRING | jc [SLICE] [OPTIONS] PARSER
- magic syntax คือการใส่
jcไว้หน้าคำสั่งหรือไฟล์/procในรูปแบบjc [SLICE] [OPTIONS] COMMANDหรือjc [SLICE] [OPTIONS] /proc/<path-to-procfile>- ไม่รองรับ command alias และ shell builtin
- ใน Python เรียกใช้แบบ
jc.parse('dig', cmd_output)- ค่าที่คืนมาอาจเป็น Python dictionary, รายการของ dictionary หรือ lazy iterable ของ streaming parser ไม่ใช่สตริง JSON
- เอกสารแพ็กเกจ Python ดูได้จาก
help('jc'),help('jc.lib')หรือ เอกสารออนไลน์
รูปแบบเอาต์พุตและ schema
- representation เริ่มต้นใช้ schema แบบเข้มงวด แยกตาม parser
- ตัวเลขที่รู้จักจะถูกแปลงเป็นค่า JSON
intหรือfloat - ค่า
Noneที่รู้จักจะถูกแปลงเป็น JSONnull - ค่า boolean ที่รู้จักก็จะถูกแปลงด้วย
- parser บางตัวเพิ่มฟิลด์เชิงความหมายเพิ่มเติม
- ตัวเลขที่รู้จักจะถูกแปลงเป็นค่า JSON
- เข้าถึง JSON ดิบก่อนการประมวลผลล่วงหน้าได้ด้วยตัวเลือก
-rของ CLI หรือparse(..., raw=True)ในไลบรารี Python - schema ของแต่ละ parser ดูได้จากลิงก์เอกสารข้างรายการ parser
- เอาต์พุต JSON โดยค่าเริ่มต้นเป็นรูปแบบ compact และใช้ตัวเลือก
-pเพื่อแสดง pretty format ได้ - ส่งออกเป็น YAML ได้ด้วยตัวเลือก
-yหรือ--yaml-out
Parser ที่รองรับและตัวอย่างการใช้งาน
- สิ่งที่รองรับประกอบด้วยคำสั่ง CLI, รูปแบบไฟล์ และ parser สำหรับสตริง
- รายการ parser ใน README รวมถึง
dig,ls,ping,ps,netstat,ifconfig,csv,xml,yaml,/etc/hosts,/etc/passwd,/proc/,systemctl,git log,jwt,url,semver, ไฟล์เกี่ยวกับx509เป็นต้น - ตัวอย่างเอาต์พุตแสดงวิธีแปลงอินพุตหลายแบบให้เป็นโครงสร้าง JSON
- เอาต์พุต
arpจะถูกแปลงเป็นฟิลด์ที่อยู่, ประเภทฮาร์ดแวร์, MAC address และ interface - ไฟล์ CSV จะถูกแปลงเป็น array ของ object ที่ใช้ header เป็น key
/etc/hostsจะถูกแปลงเป็น array ของ IP และ hostnameifconfigจะถูกแปลงเป็น object ที่มีชื่อ interface, MTU, ที่อยู่ IPv4/IPv6, counter ของ packet และ byte เป็นต้นpingจะถูกแปลงเป็น object ที่มีจำนวน packet ที่ส่งและรับ, อัตราการสูญหาย, เวลา round-trip และรายการ response
- เอาต์พุต
- ใน Ansible ใช้งานได้ในรูปแบบ filter plugin ของ collection
community.general
วิธีติดตั้ง
- ติดตั้ง
jcได้หลายวิธีpip3 install jc- repository แพ็กเกจของ OS
- binary แยกตามสถาปัตยกรรมจาก GitHub Releases
- ตัวอย่างการติดตั้งด้วยแพ็กเกจ OS ได้แก่
- Debian/Ubuntu:
apt-get install jc - Fedora:
dnf install jc - openSUSE:
zypper install jc - Arch:
pacman -S jc - macOS:
brew install jc - FreeBSD: ติดตั้งผ่าน ports
- Ansible filter plugin:
ansible-galaxy collection install community.general - FortiSOAR connector: ติดตั้งจาก FortiSOAR Connector Marketplace
- Debian/Ubuntu:
ตัวเลือกหลัก
-a/--about: แสดงข้อมูลjcและ parser เป็น JSON หรือ YAML-d/--debug: แสดงข้อความ trace เมื่อมีปัญหาในการพาร์ส และ-ddให้ข้อมูล debug ละเอียดขึ้น-h/--help: แสดง help และดูเอกสาร parser ได้ด้วยjc -h --parser_name-M/--meta-out: เพิ่ม metadata เช่น timestamp, ชื่อ parser, magic command, exit code ของ magic command ลงในเอาต์พุต-q/--quiet: ปิดข้อความเตือนของ parser และ-qqจะละเว้นข้อผิดพลาดของ streaming parser-s/--slurp: รวมอินพุตหลายบรรทัดเป็น array-u/--unbuffer: ปิดการ buffering ของเอาต์พุต-B/--bash-comp,-Z/--zsh-comp: สร้าง Bash หรือ Zsh completion script
Slice และ Slurp
- Slice ใช้ไวยากรณ์
START:STOPคล้าย Python slicing เพื่อประมวลผลเฉพาะบางส่วนของบรรทัดอินพุต - เช่น ในตารางที่มี header และ footer สามารถใช้
jc 1:-1 --asciitableหรือjc 1:4 --asciitableเพื่อแปลงเฉพาะข้อมูลตรงกลางเป็น JSON - slice ที่เป็นจำนวนบวกและ slice ว่างมีประสิทธิภาพด้านหน่วยความจำดีที่สุด ส่วน slice ที่เป็นจำนวนลบจะใช้หน่วยความจำมากกว่า
- Slurp เป็นฟีเจอร์ที่ส่งออกหลายรายการพร้อมกันเป็น array ใน parser สำหรับสตริงที่รับอินพุตบรรทัดเดียว
- ตัวอย่าง: ประมวลผลไฟล์ที่มีหลาย IP address อยู่บรรทัดละหนึ่งรายการด้วย
jc --slurp --ip-address
- ตัวอย่าง: ประมวลผลไฟล์ที่มีหลาย IP address อยู่บรรทัดละหนึ่งรายการด้วย
/procmagic syntax รองรับ slurp โดยอัตโนมัติเมื่อเลือกหลายไฟล์- เมื่อแปลงไฟล์
/procหลายไฟล์ จะเพิ่มฟิลด์_fileเพื่อให้รู้ว่า object ผลลัพธ์แต่ละตัวสอดคล้องกับไฟล์ใด
- เมื่อแปลงไฟล์
- เมื่อใช้
--meta-outร่วมกับ slurp เอาต์พุตจะเป็นโครงสร้างที่ห่อด้วย arrayresultและ object_jc_meta
Exit code และ metadata
- ข้อผิดพลาดร้ายแรงภายใน
jcจะสร้าง exit code100และหากไม่ใช่กรณีนี้จะคืนค่า0 - เมื่อใช้ magic syntax
jcจะบันทึก exit code ของโปรแกรมที่เป็นเป้าหมายการพาร์ส แล้วนำมาบวกกับ exit code ของjc- ถ้า
ifconfigเป็น1และjcเป็น0exit code รวมคือ1 - ถ้า
ifconfigเป็น0และjcเป็น100exit code รวมคือ100 - ถ้าทั้งคู่มีข้อผิดพลาด exit code รวมคือ
101
- ถ้า
- เมื่อใช้
--meta-outหรือ-Mใน magic syntax object_jc_metaจะมีข้อมูล magic command และ exit code รวมอยู่ด้วย
สีและตัวแปรสภาพแวดล้อม
- กำหนดสีของ key name, keyword, number, string ได้ด้วยตัวแปรสภาพแวดล้อม
JC_COLORS- รูปแบบคือ
JC_COLORS=<keyname_color>,<keyword_color>,<number_color>,<string_color> - ค่าสีต้องเป็นหนึ่งใน
black,red,green,yellow,blue,magenta,cyan,gray,brightblack,brightred,brightgreen,brightyellow,brightblue,brightmagenta,brightcyan,white,default
- รูปแบบคือ
- เมื่อตั้งค่าตัวแปรสภาพแวดล้อม
NO_COLORเอาต์พุตสีจะถูกปิดใช้งาน - ตัวเลือก
-Cจะบังคับใช้เอาต์พุตสี โดยมีลำดับความสำคัญเหนือกว่าตัวแปรสภาพแวดล้อมNO_COLORและตัวเลือก-m
Streaming parser
- parser ส่วนใหญ่จะอ่าน
STDINทั้งหมดเข้า memory แล้วพาร์ส จากนั้นจึง serialize เอกสาร JSON ออกมา - streaming parser บางตัวจะประมวลผลทีละบรรทัดทันทีเมื่อได้รับอินพุต และส่งออกเป็น JSON Lines หรือ NDJSON
- ตัวอย่าง:
ls-s,ping-s - สามารถลดการใช้ memory ของเอาต์พุตคำสั่งขนาดใหญ่อย่าง
ls -lR /ได้อย่างมาก และในบางกรณีอาจประมวลผลได้เร็วขึ้น
- ตัวอย่าง:
- streaming parser ใช้ร่วมกับ magic syntax ไม่ได้
- ใน pipeline ที่รันระยะยาว หากต้องการไม่ให้ข้อผิดพลาดในการพาร์สทำให้ pipe พัง สามารถใช้
-qqหรือignore_exceptions=Trueใน Python- บรรทัดที่สำเร็จจะมี
_jc_meta.success: true - บรรทัดที่ล้มเหลวจะมีฟิลด์
_jc_meta.success: false,error,line
- บรรทัดที่สำเร็จจะมี
- หากเห็นเอาต์พุตล่าช้าระหว่าง pipe เพราะ buffer ของระบบปฏิบัติการ สามารถใช้ unbuffered output ด้วย
-u- อย่างไรก็ตาม ใน data stream ขนาดใหญ่ unbuffered output อาจช้ากว่า
- ใน Python streaming parser รับอินพุตแบบ iterable และคืน object แบบ iterable เพื่อประมวลผลแบบ lazy ได้
Parser plugin
- parser plugin ภายในเครื่องสามารถวางไว้ในโฟลเดอร์
jc/jcparsersของไดเรกทอรีข้อมูลแอป- Linux/unix:
$HOME/.local/share/jc/jcparsers - macOS:
$HOME/Library/Application Support/jc/jcparsers - Windows:
$LOCALAPPDATA\jc\jc\jcparsers
- Linux/unix:
- plugin เป็นไฟล์โมดูล Python มาตรฐาน
- ใช้
jc/parsers/foo.pyหรือjc/parsers/foo_s.pyเป็น template ได้ - ชื่อไฟล์ plugin ต้องเป็นชื่อโมดูล Python ที่ถูกต้อง โดยเริ่มต้นด้วยตัวอักษร และมีได้เฉพาะตัวอักษร ตัวเลข และ underscore
- plugin ภายในเครื่องสามารถ override parser เริ่มต้นได้
Locale, timezone และความเข้ากันได้
- เพื่อผลลัพธ์ที่ดีที่สุด แนะนำให้ตั้งค่า
LC_ALLเป็นCหรือen_US.UTF-8 - ในระบบเก่าบางระบบ locale
Cไม่รองรับการเข้ารหัส UTF-8 ทำให้เอาต์พุต UTF-8 อาจถูกลดรูปเป็น ASCII และ escape sequence แบบ\\u - parser บางตัวเพิ่มฟิลด์ epoch timestamp ที่คำนวณแล้ว
- หากชื่อฟิลด์ไม่มี suffix
_utcจะถือเป็น naive timestamp ตาม timezone ท้องถิ่น - หากตรวจพบ timezone UTC ในข้อความเอาต์พุตของคำสั่ง จะกลายเป็น timezone-aware timestamp และชื่อ key จะมี suffix
_utc - timezone อื่นนอกเหนือจาก UTC ไม่รองรับในฐานะ aware timestamp
- หากชื่อฟิลด์ไม่มี suffix
- parser บางตัวแปลงเอาต์พุตเฉพาะแพลตฟอร์ม จึงจะแสดงคำเตือนเมื่อรันบนแพลตฟอร์มที่ไม่รองรับ
- แม้บนแพลตฟอร์มที่ไม่รองรับ ก็สามารถพาร์สไฟล์เอาต์พุตจากระบบอื่นได้ และปิดคำเตือนได้ด้วย
-qหรือquiet=Trueใน Python - แพลตฟอร์มที่ทดสอบแล้วรวมถึง Centos 7.7, Ubuntu 18.04/20.04, Fedora32, macOS 10.11.6/10.14.6, NixOS, FreeBSD12, Windows 10, Windows 2016 Server, Windows 2019 Server
1 ความคิดเห็น
ความคิดเห็นใน Hacker News
บน FreeBSD ปัญหานี้ถูกแก้ไปได้ระดับหนึ่งด้วย libxo:
สามารถรับเอาต์พุตแบบมีโครงสร้างได้ด้วยคำสั่งอย่าง
$ ps --libxo=json | jqมันยังไม่สมบูรณ์นัก เช่นเคยรองรับ
lsแต่ถูกถอดออกไปด้วยเหตุผลบางอย่าง และก็ไม่ใช่ว่ายูทิลิตีทุกตัวจะรองรับjcดูเหมือนเป็นวิธีแก้ชั่วคราวที่ยอดเยี่ยมซึ่งมีตัวแยกคำสั่งจำนวนมากให้ใช้ แต่ก็ยังมีข้อจำกัดตรงที่มันต้องแยกวิเคราะห์เอาต์พุตข้อความที่เดิมไม่ได้ถูกออกแบบมาเพื่อการพาร์สคงจะดีถ้ายูทิลิตีต่าง ๆ รวมตัวกันใช้แฟล็กร่วมสำหรับส่งออก เอาต์พุตแบบมีโครงสร้าง และถึงแม้ค่าเริ่มต้นแบบ PowerShell จะอาจมากเกินไปสำหรับ Unix/Linux อย่างน้อยแค่มีแฟล็กมาตรฐาน
--jsonก็ถือว่าเป็นความก้าวหน้าครั้งใหญ่แล้วhttps://wiki.freebsd.org/LibXo
https://reviews.freebsd.org/D13959
ความเข้าใจของฉันคือมันไม่ได้แค่ส่งผ่านข้อมูลที่มีโครงสร้าง แต่ส่งอ็อบเจ็กต์ทึบแสงผ่าน pipeline และยังสามารถย้อนกลับไปขั้นก่อนหน้าเพื่อเรียกเมธอดได้ด้วย: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_methods?view=powershell-7.4
ฉันชอบทั้ง wrapper อย่าง
jc,libxoและเชลล์เชิงทดลองอย่าง https://www.nushell.sh/ แต่พวกนี้เน้นการส่งต่อข้อมูลมากกว่าอ็อบเจ็กต์ที่มีเมธอดให้รันได้ข้อมูลแบบมีโครงสร้างยังให้ความรู้สึกแบบ Unix อยู่ และถ้าต้องการอ็อบเจ็กต์จริง ๆ ก็คงถึงเวลาต้องเปิด Python หรือ Ruby
ไม่ว่าเชลล์จะยอดเยี่ยมแค่ไหนและมีความสามารถด้านการเขียนโปรแกรมดีเพียงใด การรู้ว่าเมื่อไรควรขยับจาก shell script ไปเป็นภาษาโปรแกรมจริงจังก็ยังสำคัญ
jcถูกนำเสนอมาโดยตลอดว่าเป็นเครื่องมือที่เข้ามาเติมบทบาทนี้ และน่าจะตั้งใจให้เป็น สะพานเชื่อม ไปจนกว่าการรองรับ-j/--jsonจะกระจายไปทั่วเครื่องมือ Unixhttps://blog.kellybrazil.com/2019/11/26/bringing-the-unix-philosophy-to-the-21st-century/
/procจะคืนค่าเป็น ข้อมูล JSON แทนที่จะเป็นไฟล์ข้อความแบบไม่มีโครงสร้างวิธีแก้ที่มีโครงสร้างมากกว่านี้อาจเป็นการทำให้ ELF สามารถส่งออก data structure ได้ แล้วค่อย serialize data structure นั้นเป็นเอาต์พุตเทอร์มินัล จากนั้นให้ผู้ใช้เลือกส่งออกหรือประมวลผลเป็นรูปแบบอย่าง JSON, YAML ตามต้องการ
จำยูทิลิตีที่แน่ชัดไม่ได้ แต่อาจจะเป็น
iostatซึ่งฟอร์แมตบรรทัด JSON output ด้วย string interpolation แล้วทำให้ได้เอาต์พุตพังหมดในบางชุดของแฟล็กไม่แน่ใจว่าตอนนี้ดีขึ้นหรือยัง แต่เมื่อมีตัวเลือกเรื่องช่วงเวลา ฉันคาดหวังรูปแบบอย่าง JSON lines
ในแง่ usability ฉันมองว่า PowerShell และ kubectl นำหน้า libxo ไปไกลมาก
https://github.com/Juniper/libxo
https://libxo.readthedocs.io/en/latest/
ไอเดียนั้นดีมากจริง ๆ แต่พอคิดเรื่องการดูแลรักษาแล้วก็เริ่มกังวล
ถ้าคำนึงถึงเวอร์ชัน ความเปลี่ยนแปลงของเอาต์พุตตามแฟล็กคำสั่งต่าง ๆ มันดูเหมือนนรกของการบำรุงรักษา และการใช้งานจริงก็คงใช้ได้ดีในบางกรณี แต่พอเกินกรณีพื้นฐานไป ความแปลกใหม่คงหายไปเร็ว
นอกจากนี้ การใช้
--กับตัวเลือกของเครื่องมือก็ดูไม่ค่อยดีนักถ้าทุก parser ใหม่ต้องมีแฟล็กใหม่เพิ่มเข้ามา help หรือ man page อาจยาวเป็นหลายพันบรรทัด
ถ้ายูทิลิตีตัวใดตัดสินใจรองรับการส่งออก JSON ของตัวเอง หลังจากนั้นเครื่องมือนี้ก็แค่ delegate ไปใช้ฟังก์ชันนั้นได้
jcนำหน้าคำสั่งได้แบบjc lsพารามิเตอร์
--cmdช่วยให้ประมวลผลข้อมูลก่อนแปลงได้ จึงนับว่าเป็นไอเดียที่ดีด้วยซ้ำตัวอย่างเช่น คุณอาจอยาก
grepรายการก่อนจะแปลงในแง่การบำรุงรักษา เอาต์พุตของคำสั่ง Unix พื้นฐานถ้าเปลี่ยนมากเกินไปก็จะทำให้ไม่ใช่แค่เครื่องมือนี้ แต่สคริปต์อีกจำนวนมหาศาลพังด้วย ดังนั้นมันอาจไม่ได้พังบ่อยอย่างที่คิดเพราะการอัปเดตไบนารีอื่น ๆ
ชุด parser ส่วนกลาง ที่ดูแลดีชุดเดียวย่อมดีกว่า parser เอาต์พุตเฉพาะกิจที่กระจัดกระจายไปทั่ว แต่ถ้าต้องการ JSON output โดยตรงเพื่อทำงานที่ซับซ้อนจริง ๆ ก็ไม่อยากให้การพาร์สกลายเป็นอีกปัญหาที่เพิ่มเข้ามา
ถ้าจะใช้สิ่งนี้ให้สะดวก สุดท้ายก็คงต้องส่ง PR พร้อม test case เพิ่มเติมสำหรับทุกอย่างที่ฉันตั้งใจจะใช้
ยังไงเสียฉันก็ต้องเขียน test เหล่านั้นเองอยู่แล้ว
คนต้องช่วยกันส่งข้อมูลการพาร์สของเครื่องมือที่จำเป็นเข้ามา และผู้ใช้ก็ต้องช่วยกันทำให้มันอัปเดตอยู่เสมอให้ได้ง่ายที่สุด
แม้ Nushell จะมีแนวทางต่างออกไป แต่โดยมากก็ไปถึงจุดเดียวกันคือ ข้อมูลแบบมีโครงสร้างจากคำสั่งเชลล์
โดยหลักแล้วเป็นวิธีที่ตัวเชลล์เองรับบทบาทนั้น
http://www.nushell.sh/
from jsonอยู่แล้ว จึงเข้ากันกับ JC ได้ดีทีเดียวก่อนหน้านี้เคยอัดวิดีโอแสดงฟีเจอร์ดี ๆ ของ Nushell หลายอย่างไว้ และช่วงประมาณนาทีที่ 19 ก็พูดถึงการใช้ร่วมกับ
jc: https://www.youtube.com/watch?v=KF5dtxVsn1Eตอนนั้นกำลังจะเขียนสคริปต์เพื่อไล่ดูไฟล์ในไดเรกทอรีที่ตรงกับแพตเทิร์นหนึ่ง แล้วลบไฟล์ที่มีเวลาแก้ไขห่างกันไม่เกิน 10 นาที เลยนึกขึ้นได้ว่า Nushell น่าจะเหมาะกับงานแบบนี้
พอลองเล่นอยู่แป๊บเดียวก็เริ่มจับทางได้ และตอนนี้ก็ติดใจไปแล้ว
แม้จะเป็นข้อมูลที่ไม่มีโครงสร้าง ถ้าสามารถแปลงให้อยู่ในรูปแบบอย่าง รายการของเรคอร์ด แล้วค่อยประมวลผลได้ ก็ทรงพลังมาก
ในความหมายหนึ่ง การที่ทุกอย่างอยู่ในไฟล์นั้นยอดเยี่ยมมาก และนั่นก็คือข้อตกลงของ Unix ซึ่งใน Plan 9 ก็ขยายแนวคิดนี้ไปอีก
แต่การที่ไฟล์ไม่มีโครงสร้าง หรือแต่ละไฟล์มีรูปแบบของตัวเอง ก็เป็นตัวถ่วงไม่แพ้กัน
แค่จะพาร์สไฟล์ล็อกของ nginx สักไฟล์ด้วย
awkอย่างเดียวก็อาจน่ารำคาญได้แล้วข้อเสียใหญ่อย่างหนึ่งคือใน user space ของ Linux มันยากที่จะผลักดันการเขียนระบบใหม่ครั้งใหญ่หรือเปลี่ยนการออกแบบในระดับกว้าง
อยากได้เชลล์ที่ฉลาดขึ้น ชอบไฟล์เหมือนเดิม และยังมีหนังสือ
awkวางอยู่ข้างตัว แต่ตอนนี้รู้สึกว่าถึงเวลาต้องปรับปรุงเรื่อง การพาร์สข้อมูล อย่างจริงจังแล้วถ้าโปรแกรมตัดสินใจเองได้ว่าจะเรนเดอร์สีหรือไม่ ก็น่าจะตัดสินใจได้เหมือนกันว่าจะส่งออกผลลัพธ์แบบมีโครงสร้างหรือไม่
เพราะ text UI แบบไหนก็นำไปใช้เหมือน API ได้ ข้อความที่มนุษย์อ่านง่ายจึงได้ความสำคัญก่อน
ทำให้การเขียนเชลล์สคริปต์คล้ายกับการทำส่วนขยายเบราว์เซอร์ของบุคคลที่สาม
คือดูเอา เดาเอา แล้วค่อยปะติดปะต่อ parser จากสิ่งที่เดาไว้และหวังว่ามันจะใช้ได้
ถ้ามี standard output ตัวที่สามสำหรับเนื้อหาที่เครื่องอ่านได้ก็คงดี
เทอร์มินัลจะไม่แสดงผลนี้โดยปริยาย แต่ถ้ามีการ pipe ก็ให้ stream นี้ถูก pipe ไปแทน ควรเป็น JSONL และระบุสัญญาไว้ในคู่มือคำสั่ง
แบบนั้น standard output ก็ยังคงไว้สำหรับมนุษย์ได้ และถ้าจะพาร์สก็ทำโดยรู้ตัวว่ามันทำได้แต่เปราะบาง
แน่นอนว่านี่เป็นแนวคิดที่ทำลาย backward compatibility แบบสิ้นเชิง และถ้าจะรื้อ CLI แล้วออกแบบใหม่ให้ทันสมัยแบบสุดโต่งจริง ๆ รายการสิ่งที่อยากเปลี่ยนก็ยังยาวอีกมาก
การผลักดันให้เกิดการปรับปรุงก็ยากมากจริง ๆ และถ้ามีใครอย่าง Lennart พยายามกวาดของเก่าคร่ำครึออก ก็จะเกิดดราม่าตามมาทันที
JSON เองก็ยังไม่สมบูรณ์
JSON เป็นไอเดียที่ใช้ได้พอสมควร แต่ถ้าจะทำให้ดีจริง ๆ ก็ต้องการฟอร์แมตที่เผยสิ่งอย่างชนิดข้อมูลได้
มันควรใกล้กับ PowerShell มากกว่า เพื่อให้จัดการตัวเลขเป็นตัวเลขจริง ๆ และทำเรื่องน่าทึ่งอย่างคำนวณส่วนต่างของวันที่ด้วย
$a - $bได้อยากเห็นสิ่งนี้เกิดขึ้นใน GNU coreutils
ปัญหาคือมันหยั่งรากลึกกับ .NET และอ็อบเจ็กต์มากเกินไป จนทำให้ผสานกับคำสั่ง native เดิม ๆ บนแพลตฟอร์มต่าง ๆ ได้ยากมาก
เพราะโดยแก่นแล้วมันกำลังทำงานแบบเดียวกันอยู่แล้ว
แต่สุดท้ายเป้าหมายน่าจะยังเป็นให้เครื่องมือระดับบนเริ่มเห็นคุณค่าและให้ structured output มาโดยตรง
เจ๋งดี
สนับสนุนอย่างมากให้เครื่องมือ CLI รองรับ JSON output แบบสมเหตุสมผล และสิ่งอย่าง https://github.com/WireGuard/wireguard-tools/blob/master/contrib/json/wg-json กับ
|ConvertTo-Jsonของ PowerShell ก็เป็นส่วนสำคัญมากของงานอัตโนมัติด้านแอดมินและมอนิเตอร์ริงแต่คำว่า สมเหตุสมผล ตรงนี้แบกรับความหมายไว้เยอะมาก และโลกความจริงก็ยังเป็นโลกความจริง
บ่อยครั้งที่ผลลัพธ์แม้จะเป็น JSON ในเชิงเทคนิค เช่น วิธีเติม
Jต่อท้ายคำสั่งของ LSI/Broadcom StorCLI หรือพวก wrapper ที่ซ่อน COM ใน PowerShell กลับซับซ้อนเกินเหตุหรือแทบไร้ประโยชน์ จนสุดท้ายต้องย้อนกลับไปใช้วิธีแก้ขัดแบบ “เอา plain text มาไล่ regex ก็แล้วกัน”ถึงอย่างนั้นก็คิดว่าจะลองดูแน่นอน
ถ้าการพาร์สผลลัพธ์
digในตัวอย่างแรกเป็นตัวแทนของสิ่งที่ทำได้อย่างเสถียร ก็น่าสนใจไม่น้อยคิดว่าไวยากรณ์พื้นฐานควรเป็น
jc dig example.comเพราะ
dig example.com | jc --digทำให้ต้องมาเดาทีหลังว่าคำสั่งก่อนหน้าถูกเรียกด้วยแฟล็กและพารามิเตอร์อะไรบ้างเพื่อจะพาร์สผลลัพธ์การที่ทุกผลลัพธ์เป็นอ็อบเจ็กต์คือหนึ่งในสิ่งที่ชอบที่สุดใน PowerShell
ทุกครั้งที่ต้องเขียน bash script ก็จะคิดถึงมัน
ขอคารวะคนที่ตัดสินใจจะดูแลรักษาสิ่งนี้
ถ้าออกมาเป็นแนว
aws s3 ls | jc --aws=1.2.3คงเป็นฝันร้ายทำให้นึกถึงโปรแกรม
fileบน Linux หรือ Unix และเหล่าฮีโร่ที่ดูแลมันpluginsได้ เช่น แยกไว้เป็นคำสั่งเชลล์ต่างหาก ก็น่าจะโยนภาระการดูแลบางส่วนไปให้ ผู้เขียนปลั๊กอิน ได้สงสัยว่ามีใครรู้จักรายชื่อเครื่องมือบรรทัดคำสั่งแบบ Unix สมัยใหม่ที่รับออปชัน
--jsonบ้างการเพิ่มข้อมูลแบบนั้นไว้ในรีโพซิทอรีนี้ก็น่าจะมีประโยชน์
ipซึ่งเป็นเครื่องมือสมัยใหม่ที่ใช้แทนifconfigก็รองรับ JSONlldpctlก็รองรับเช่นกันAnsible ให้รายละเอียดของระบบในรูปแบบ JSON ที่เรียกว่า
factsและถูกออกแบบมาให้ระบบอัตโนมัตินำไปใช้lsblkรับแฟล็ก--jsonและให้ข้อมูลได้มากมายลอง
lsblk --json --output-allได้มีประโยชน์มากเมื่อสคริปต์ต้องตรวจสอบดิสก์และพาร์ทิชันของระบบ
-T jsonเป็นโปรเจ็กต์ที่น่าสนใจ
แต่คิดว่าในขั้นแรกจะใช้บางอย่างอย่าง textfsm เป็นตัวพาร์ส
textfsm ถูกใช้บ่อยในการพาร์สเอาต์พุต CLI ของอุปกรณ์เครือข่าย
https://github.com/google/textfsm