2 คะแนน โดย GN⁺ 2023-12-10 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • 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] PARSER
    • cat FILE | jc [SLICE] [OPTIONS] PARSER
    • echo 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 ที่รู้จักจะถูกแปลงเป็น JSON null
    • ค่า boolean ที่รู้จักก็จะถูกแปลงด้วย
    • parser บางตัวเพิ่มฟิลด์เชิงความหมายเพิ่มเติม
  • เข้าถึง 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 และ hostname
    • ifconfig จะถูกแปลงเป็น 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

ตัวเลือกหลัก

  • -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
  • /proc magic syntax รองรับ slurp โดยอัตโนมัติเมื่อเลือกหลายไฟล์
    • เมื่อแปลงไฟล์ /proc หลายไฟล์ จะเพิ่มฟิลด์ _file เพื่อให้รู้ว่า object ผลลัพธ์แต่ละตัวสอดคล้องกับไฟล์ใด
  • เมื่อใช้ --meta-out ร่วมกับ slurp เอาต์พุตจะเป็นโครงสร้างที่ห่อด้วย array result และ object _jc_meta

Exit code และ metadata

  • ข้อผิดพลาดร้ายแรงภายใน jc จะสร้าง exit code 100 และหากไม่ใช่กรณีนี้จะคืนค่า 0
  • เมื่อใช้ magic syntax jc จะบันทึก exit code ของโปรแกรมที่เป็นเป้าหมายการพาร์ส แล้วนำมาบวกกับ exit code ของ jc
    • ถ้า ifconfig เป็น 1 และ jc เป็น 0 exit code รวมคือ 1
    • ถ้า ifconfig เป็น 0 และ jc เป็น 100 exit 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
  • 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
  • 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 ความคิดเห็น

 
GN⁺ 2023-12-10
ความคิดเห็นใน Hacker News
  • บน FreeBSD ปัญหานี้ถูกแก้ไปได้ระดับหนึ่งด้วย libxo:
    สามารถรับเอาต์พุตแบบมีโครงสร้างได้ด้วยคำสั่งอย่าง $ ps --libxo=json | jq
    มันยังไม่สมบูรณ์นัก เช่นเคยรองรับ ls แต่ถูกถอดออกไปด้วยเหตุผลบางอย่าง และก็ไม่ใช่ว่ายูทิลิตีทุกตัวจะรองรับ
    jc ดูเหมือนเป็นวิธีแก้ชั่วคราวที่ยอดเยี่ยมซึ่งมีตัวแยกคำสั่งจำนวนมากให้ใช้ แต่ก็ยังมีข้อจำกัดตรงที่มันต้องแยกวิเคราะห์เอาต์พุตข้อความที่เดิมไม่ได้ถูกออกแบบมาเพื่อการพาร์ส
    คงจะดีถ้ายูทิลิตีต่าง ๆ รวมตัวกันใช้แฟล็กร่วมสำหรับส่งออก เอาต์พุตแบบมีโครงสร้าง และถึงแม้ค่าเริ่มต้นแบบ PowerShell จะอาจมากเกินไปสำหรับ Unix/Linux อย่างน้อยแค่มีแฟล็กมาตรฐาน --json ก็ถือว่าเป็นความก้าวหน้าครั้งใหญ่แล้ว
    https://wiki.freebsd.org/LibXo
    https://reviews.freebsd.org/D13959

    • PowerShell ไปไกลกว่า JSON อีกขั้น เพราะรองรับ อ็อบเจ็กต์ที่แก้ไขเปลี่ยนแปลงได้จริง
      ความเข้าใจของฉันคือมันไม่ได้แค่ส่งผ่านข้อมูลที่มีโครงสร้าง แต่ส่งอ็อบเจ็กต์ทึบแสงผ่าน 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 จะกระจายไปทั่วเครื่องมือ Unix
      https://blog.kellybrazil.com/2019/11/26/bringing-the-unix-philosophy-to-the-21st-century/
    • ใน SerenityOS ก็มีแนวคิดคล้ายกัน โดยรายการใต้ /proc จะคืนค่าเป็น ข้อมูล JSON แทนที่จะเป็นไฟล์ข้อความแบบไม่มีโครงสร้าง
      วิธีแก้ที่มีโครงสร้างมากกว่านี้อาจเป็นการทำให้ ELF สามารถส่งออก data structure ได้ แล้วค่อย serialize data structure นั้นเป็นเอาต์พุตเทอร์มินัล จากนั้นให้ผู้ใช้เลือกส่งออกหรือประมวลผลเป็นรูปแบบอย่าง JSON, YAML ตามต้องการ
    • Libxo ฟังดูดีมากในเชิงทฤษฎี แต่ดูเหมือนว่าแทนที่แอปพลิเคชันจะส่งโครงสร้างให้ libxo แล้วปล่อยให้มันจัดการการฟอร์แมต แอปกลับต้องเขียน logic ของแต่ละรูปแบบเอาต์พุตเอง
      จำยูทิลิตีที่แน่ชัดไม่ได้ แต่อาจจะเป็น iostat ซึ่งฟอร์แมตบรรทัด JSON output ด้วย string interpolation แล้วทำให้ได้เอาต์พุตพังหมดในบางชุดของแฟล็ก
      ไม่แน่ใจว่าตอนนี้ดีขึ้นหรือยัง แต่เมื่อมีตัวเลือกเรื่องช่วงเวลา ฉันคาดหวังรูปแบบอย่าง JSON lines
      ในแง่ usability ฉันมองว่า PowerShell และ kubectl นำหน้า libxo ไปไกลมาก
    • Libxo อยู่ในระบบพื้นฐานของ FreeBSD แต่ก็ใช้งานได้ทั่วไปด้วย
      https://github.com/Juniper/libxo
      https://libxo.readthedocs.io/en/latest/
  • ไอเดียนั้นดีมากจริง ๆ แต่พอคิดเรื่องการดูแลรักษาแล้วก็เริ่มกังวล
    ถ้าคำนึงถึงเวอร์ชัน ความเปลี่ยนแปลงของเอาต์พุตตามแฟล็กคำสั่งต่าง ๆ มันดูเหมือนนรกของการบำรุงรักษา และการใช้งานจริงก็คงใช้ได้ดีในบางกรณี แต่พอเกินกรณีพื้นฐานไป ความแปลกใหม่คงหายไปเร็ว
    นอกจากนี้ การใช้ -- กับตัวเลือกของเครื่องมือก็ดูไม่ค่อยดีนัก
    ถ้าทุก parser ใหม่ต้องมีแฟล็กใหม่เพิ่มเข้ามา help หรือ man page อาจยาวเป็นหลายพันบรรทัด

    • ถ้ามองว่านี่เป็น shim ที่ขอบเขตความรับผิดชอบจะค่อย ๆ เล็กลงเมื่อยูทิลิตี command line ต่าง ๆ รองรับการส่งออก JSON มากขึ้น ก็ดูโอเค
      ถ้ายูทิลิตีตัวใดตัดสินใจรองรับการส่งออก JSON ของตัวเอง หลังจากนั้นเครื่องมือนี้ก็แค่ delegate ไปใช้ฟังก์ชันนั้นได้
    • ถ้าเลื่อนลงไปอ่านเอกสารอีกหน่อย จะเห็นว่าสามารถใส่ jc นำหน้าคำสั่งได้แบบ jc ls
      พารามิเตอร์ --cmd ช่วยให้ประมวลผลข้อมูลก่อนแปลงได้ จึงนับว่าเป็นไอเดียที่ดีด้วยซ้ำ
      ตัวอย่างเช่น คุณอาจอยาก grep รายการก่อนจะแปลง
      ในแง่การบำรุงรักษา เอาต์พุตของคำสั่ง Unix พื้นฐานถ้าเปลี่ยนมากเกินไปก็จะทำให้ไม่ใช่แค่เครื่องมือนี้ แต่สคริปต์อีกจำนวนมหาศาลพังด้วย ดังนั้นมันอาจไม่ได้พังบ่อยอย่างที่คิดเพราะการอัปเดตไบนารีอื่น ๆ
    • อีกมุมหนึ่งก็ยังรู้สึกลังเล
      ชุด parser ส่วนกลาง ที่ดูแลดีชุดเดียวย่อมดีกว่า parser เอาต์พุตเฉพาะกิจที่กระจัดกระจายไปทั่ว แต่ถ้าต้องการ JSON output โดยตรงเพื่อทำงานที่ซับซ้อนจริง ๆ ก็ไม่อยากให้การพาร์สกลายเป็นอีกปัญหาที่เพิ่มเข้ามา
      ถ้าจะใช้สิ่งนี้ให้สะดวก สุดท้ายก็คงต้องส่ง PR พร้อม test case เพิ่มเติมสำหรับทุกอย่างที่ฉันตั้งใจจะใช้
      ยังไงเสียฉันก็ต้องเขียน test เหล่านั้นเองอยู่แล้ว
    • เรื่องนี้ต้องอาศัยความร่วมมือ
      คนต้องช่วยกันส่งข้อมูลการพาร์สของเครื่องมือที่จำเป็นเข้ามา และผู้ใช้ก็ต้องช่วยกันทำให้มันอัปเดตอยู่เสมอให้ได้ง่ายที่สุด
    • นี่เป็นหนึ่งในกรณีใช้งานที่ดีกว่าสำหรับ LLM ซึ่งแสดงความสามารถได้ดีในการแปลงข้อความที่ไม่มีโครงสร้างให้เป็นอ็อบเจ็กต์ที่มีโครงสร้าง
  • แม้ Nushell จะมีแนวทางต่างออกไป แต่โดยมากก็ไปถึงจุดเดียวกันคือ ข้อมูลแบบมีโครงสร้างจากคำสั่งเชลล์
    โดยหลักแล้วเป็นวิธีที่ตัวเชลล์เองรับบทบาทนั้น
    http://www.nushell.sh/

    • ใน Nushell มีโอเปอเรชัน from json อยู่แล้ว จึงเข้ากันกับ JC ได้ดีทีเดียว
      ก่อนหน้านี้เคยอัดวิดีโอแสดงฟีเจอร์ดี ๆ ของ Nushell หลายอย่างไว้ และช่วงประมาณนาทีที่ 19 ก็พูดถึงการใช้ร่วมกับ jc: https://www.youtube.com/watch?v=KF5dtxVsn1E
    • หลังจาก Nushell เปิดตัวครั้งแรกก็แวะกลับไปดูเป็นครั้งคราว แต่เพิ่งมาเข้าใจแก่นของมันอย่างแท้จริงเมื่อราวหนึ่งหรือสองเดือนก่อน
      ตอนนั้นกำลังจะเขียนสคริปต์เพื่อไล่ดูไฟล์ในไดเรกทอรีที่ตรงกับแพตเทิร์นหนึ่ง แล้วลบไฟล์ที่มีเวลาแก้ไขห่างกันไม่เกิน 10 นาที เลยนึกขึ้นได้ว่า Nushell น่าจะเหมาะกับงานแบบนี้
      พอลองเล่นอยู่แป๊บเดียวก็เริ่มจับทางได้ และตอนนี้ก็ติดใจไปแล้ว
      แม้จะเป็นข้อมูลที่ไม่มีโครงสร้าง ถ้าสามารถแปลงให้อยู่ในรูปแบบอย่าง รายการของเรคอร์ด แล้วค่อยประมวลผลได้ ก็ทรงพลังมาก
  • ในความหมายหนึ่ง การที่ทุกอย่างอยู่ในไฟล์นั้นยอดเยี่ยมมาก และนั่นก็คือข้อตกลงของ Unix ซึ่งใน Plan 9 ก็ขยายแนวคิดนี้ไปอีก
    แต่การที่ไฟล์ไม่มีโครงสร้าง หรือแต่ละไฟล์มีรูปแบบของตัวเอง ก็เป็นตัวถ่วงไม่แพ้กัน
    แค่จะพาร์สไฟล์ล็อกของ nginx สักไฟล์ด้วย awk อย่างเดียวก็อาจน่ารำคาญได้แล้ว
    ข้อเสียใหญ่อย่างหนึ่งคือใน user space ของ Linux มันยากที่จะผลักดันการเขียนระบบใหม่ครั้งใหญ่หรือเปลี่ยนการออกแบบในระดับกว้าง
    อยากได้เชลล์ที่ฉลาดขึ้น ชอบไฟล์เหมือนเดิม และยังมีหนังสือ awk วางอยู่ข้างตัว แต่ตอนนี้รู้สึกว่าถึงเวลาต้องปรับปรุงเรื่อง การพาร์สข้อมูล อย่างจริงจังแล้ว
    ถ้าโปรแกรมตัดสินใจเองได้ว่าจะเรนเดอร์สีหรือไม่ ก็น่าจะตัดสินใจได้เหมือนกันว่าจะส่งออกผลลัพธ์แบบมีโครงสร้างหรือไม่

    • ส่วนหนึ่งของปัญหาคือผลลัพธ์ของคำสั่งเป็นทั้ง ส่วนติดต่อผู้ใช้และ API
      เพราะ text UI แบบไหนก็นำไปใช้เหมือน API ได้ ข้อความที่มนุษย์อ่านง่ายจึงได้ความสำคัญก่อน
      ทำให้การเขียนเชลล์สคริปต์คล้ายกับการทำส่วนขยายเบราว์เซอร์ของบุคคลที่สาม
      คือดูเอา เดาเอา แล้วค่อยปะติดปะต่อ parser จากสิ่งที่เดาไว้และหวังว่ามันจะใช้ได้
      ถ้ามี standard output ตัวที่สามสำหรับเนื้อหาที่เครื่องอ่านได้ก็คงดี
      เทอร์มินัลจะไม่แสดงผลนี้โดยปริยาย แต่ถ้ามีการ pipe ก็ให้ stream นี้ถูก pipe ไปแทน ควรเป็น JSONL และระบุสัญญาไว้ในคู่มือคำสั่ง
      แบบนั้น standard output ก็ยังคงไว้สำหรับมนุษย์ได้ และถ้าจะพาร์สก็ทำโดยรู้ตัวว่ามันทำได้แต่เปราะบาง
      แน่นอนว่านี่เป็นแนวคิดที่ทำลาย backward compatibility แบบสิ้นเชิง และถ้าจะรื้อ CLI แล้วออกแบบใหม่ให้ทันสมัยแบบสุดโต่งจริง ๆ รายการสิ่งที่อยากเปลี่ยนก็ยังยาวอีกมาก
    • เมื่อครึ่งศตวรรษก่อนมีไอเดียที่ค่อนข้างดีเกิดขึ้นหลายอย่าง แต่น่าหงุดหงิดที่หลายคนไม่มองว่านั่นคือสิ่งที่ควรพัฒนาให้ดีขึ้น กลับรับมาเหมือนเป็นคัมภีร์
      การผลักดันให้เกิดการปรับปรุงก็ยากมากจริง ๆ และถ้ามีใครอย่าง Lennart พยายามกวาดของเก่าคร่ำครึออก ก็จะเกิดดราม่าตามมาทันที
      JSON เองก็ยังไม่สมบูรณ์
      JSON เป็นไอเดียที่ใช้ได้พอสมควร แต่ถ้าจะทำให้ดีจริง ๆ ก็ต้องการฟอร์แมตที่เผยสิ่งอย่างชนิดข้อมูลได้
      มันควรใกล้กับ PowerShell มากกว่า เพื่อให้จัดการตัวเลขเป็นตัวเลขจริง ๆ และทำเรื่องน่าทึ่งอย่างคำนวณส่วนต่างของวันที่ด้วย $a - $b ได้
    • การปรับปรุงที่ง่ายกว่าคือให้เครื่องมือ CLI ทุกตัวรองรับ JSON output ผ่านอาร์กิวเมนต์บรรทัดคำสั่ง
      อยากเห็นสิ่งนี้เกิดขึ้นใน GNU coreutils
    • ตัวเลือกอย่าง PowerShell ก็มีอยู่เสมอ
      ปัญหาคือมันหยั่งรากลึกกับ .NET และอ็อบเจ็กต์มากเกินไป จนทำให้ผสานกับคำสั่ง native เดิม ๆ บนแพลตฟอร์มต่าง ๆ ได้ยากมาก
    • ในงานพาร์ส server log ก็น่าเสียดายที่เราไม่สามารถดึงฟังก์ชันบางส่วนออกมาจาก logstash ได้
      เพราะโดยแก่นแล้วมันกำลังทำงานแบบเดียวกันอยู่แล้ว
      แต่สุดท้ายเป้าหมายน่าจะยังเป็นให้เครื่องมือระดับบนเริ่มเห็นคุณค่าและให้ 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 บ้าง
    การเพิ่มข้อมูลแบบนั้นไว้ในรีโพซิทอรีนี้ก็น่าจะมีประโยชน์

    • บน FreeBSD รองรับแทบทุกอย่างผ่าน libxo
    • แม้จะไม่มีรายชื่อ แต่ ip ซึ่งเป็นเครื่องมือสมัยใหม่ที่ใช้แทน ifconfig ก็รองรับ JSON
      lldpctl ก็รองรับเช่นกัน
      Ansible ให้รายละเอียดของระบบในรูปแบบ JSON ที่เรียกว่า facts และถูกออกแบบมาให้ระบบอัตโนมัตินำไปใช้
    • lsblk รับแฟล็ก --json และให้ข้อมูลได้มากมาย
      ลอง lsblk --json --output-all ได้
      มีประโยชน์มากเมื่อสคริปต์ต้องตรวจสอบดิสก์และพาร์ทิชันของระบบ
    • TShark ซึ่งเป็นเครื่องมือคู่ CLI ของ Wireshark รองรับผ่านแฟล็ก -T json
    • อาจไม่ใช่คำตอบที่ตั้งใจไว้ แต่ก็มี AWS CLI
  • เป็นโปรเจ็กต์ที่น่าสนใจ
    แต่คิดว่าในขั้นแรกจะใช้บางอย่างอย่าง textfsm เป็นตัวพาร์ส
    textfsm ถูกใช้บ่อยในการพาร์สเอาต์พุต CLI ของอุปกรณ์เครือข่าย
    https://github.com/google/textfsm