0Pricing
Linux Command Line & Bash Scripting Mastery · บทเรียน

การกรองและเลือก JSON ด้วยไปป์ไลน์ jq

เข้าถึงออบเจกต์ซ้อนกันและอาร์เรย์ด้วยตัวเลือก ท่อ และตัวกรอง select ของ jq

การกรองและเลือก JSON ด้วยไปป์ไลน์ jq เป็นบทเรียน Linux Command Line & Bash Scripting Mastery ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Linux Command Line & Bash Scripting Mastery และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน

jq คืออะไร และเหตุใดจึงควรใช้

jq เป็นเครื่องมือบรรทัดคำสั่งที่มีขนาดเล็กแต่ทรงพลังสำหรับแยกวิเคราะห์ กรอง และแปลงข้อมูล JSON โดยเป็นเสมือน sed สำหรับ JSON — ส่ง JSON เข้าไปแล้วรับผลลัพธ์ที่มีโครงสร้างกลับมา

  • ติดตั้งไว้ล่วงหน้าในดิสทริบิวชัน Linux ส่วนใหญ่ หรือพร้อมติดตั้งผ่าน apt install jq / brew install jq
  • ทำงานร่วมกับไปป์ไลน์ของเชลล์ได้อย่างราบรื่นกับ curl cat และเครื่องมืออื่น ๆ
  • รองรับการกรอง การแมป การลดรูป และการแปลงรูปแบบ

รูปแบบการเรียกใช้พื้นฐานคือ jq '<filter>' file.json หรือส่งผ่านไปป์ด้วย cat file.json | jq '<filter>' ตัวกรอง . (จุด) คือเอกลักษณ์ ซึ่งจะแสดงเอกสารทั้งฉบับในรูปแบบอ่านง่าย

# Pretty-print a JSON file
jq '.' data.json

# Or pipe from curl
curl -s https://api.github.com/users/torvalds | jq '.'

การเลือกฟิลด์ของออบเจ็กต์ด้วยสัญกรณ์จุด

หากต้องการเข้าถึงฟิลด์ในออบเจ็กต์ JSON ให้ใช้สัญกรณ์จุด: .fieldName คุณสามารถต่อเซเล็กเตอร์เพื่อเข้าถึงออบเจ็กต์ที่ซ้อนกันได้

  • .name — ฟิลด์ระดับบนสุด
  • .address.city — ฟิลด์ที่ซ้อนกัน
  • ."field-with-dash" — ฟิลด์ที่มีอักขระพิเศษต้องใส่อัญประกาศ

หากไม่มีฟิลด์นั้น jq จะคืนค่า null แทนการแจ้งข้อผิดพลาด จึงใช้งานในสคริปต์ได้อย่างปลอดภัยโดยไม่ต้องตรวจสอบค่า null เพิ่มเติมสำหรับฟิลด์ที่อาจมีหรือไม่มีก็ได้

# Given: {"name":"Alice","address":{"city":"Berlin","zip":"10115"}}
echo '{"name":"Alice","address":{"city":"Berlin","zip":"10115"}}' | jq '.name'
# Output: "Alice"

echo '{"name":"Alice","address":{"city":"Berlin","zip":"10115"}}' | jq '.address.city'
# Output: "Berlin"

การเข้าถึงสมาชิกอาร์เรย์และการวนซ้ำ

เข้าถึงอาร์เรย์ JSON ด้วยสัญกรณ์วงเล็บเหลี่ยม jq ใช้ดัชนีที่เริ่มจากศูนย์

  • .items[0] — สมาชิกตัวแรก
  • .items[-1] — สมาชิกตัวสุดท้าย
  • .items[1:3] — ส่วนย่อย (ตั้งแต่ดัชนี 1 จนถึงก่อนดัชนี 3)
  • .items[] — แยกอาร์เรย์: ส่งออกสมาชิกแต่ละตัวเป็นค่าแยกกัน (นี่คือตัววนซ้ำ)

ตัววนซ้ำ [] เป็นพื้นฐานสำคัญของไปป์ไลน์ jq เพราะช่วยให้ใช้ตัวกรองถัดไปกับสมาชิกแต่ละตัวได้อย่างอิสระ

# Given an array of users
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Carol"}]' | jq '.[0]'
# Output: {"name":"Alice"}

# Iterate all elements and extract .name from each
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Carol"}]' | jq '.[].name'
# Output:
# "Alice"
# "Bob"
# "Carol"

การสร้างไปป์ไลน์ jq ด้วยตัวดำเนินการไปป์

เช่นเดียวกับไปป์ของเชลล์ | jq มีตัวดำเนินการไปป์ภายในของตนเอง ซึ่งส่งผลลัพธ์จากตัวกรองหนึ่งไปเป็นข้อมูลนำเข้าของตัวกรองถัดไป

  • jq '.users[] | .name' — วนซ้ำสมาชิกผู้ใช้ แล้วดึงชื่อของแต่ละคน
  • jq '.data | .items[] | .id' — เข้าถึงข้อมูล แยกสมาชิก items แล้วดึง id

ไปป์ภายในนิพจน์ jq ช่วยให้สร้างการแปลงข้อมูลที่ซับซ้อนทีละขั้น แต่ละขั้นจะได้รับทุกค่าที่ขั้นก่อนหน้าสร้างขึ้น รวมถึงหลายค่าจากตัววนซ้ำ

ข้อสังเกตสำคัญ: เมื่อตัววนซ้ำสร้างค่า N ค่า ตัวกรองปลายทางทุกตัวจะทำงาน N ครั้ง ครั้งละหนึ่งค่า

# Nested pipeline: navigate -> iterate -> extract
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' \
  | jq '.users[] | .name'
# Output:
# "Alice"
# "Bob"

# Chain more stages
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' \
  | jq '.users[] | .age'
# Output:
# 30
# 25

การกรองด้วย select()

ตัวกรอง select(condition) จะส่งค่าต่อเมื่อเงื่อนไขเป็นจริงเท่านั้น หากไม่เป็นจริงจะไม่สร้างผลลัพธ์ใด ๆ ซึ่งเทียบเท่ากับ grep ใน jq หรือ WHERE ใน SQL

  • select(.age > 18) — เก็บออบเจ็กต์ที่อายุสูงกว่า 18
  • select(.status == "active") — ตรวจสอบความเท่ากัน
  • select(.name | startswith("A")) — การทดสอบสตริงที่ซ้อนกัน

ใช้ select ร่วมกับตัววนซ้ำเพื่อกรองอาร์เรย์: .items[] | select(.active) จะส่งออกเฉพาะสมาชิกที่ .active เป็นค่าจริง

# Filter array elements by a condition
echo '[{"name":"Alice","age":30},{"name":"Bob","age":17},{"name":"Carol","age":25}]' \
  | jq '.[] | select(.age >= 18) | .name'
# Output:
# "Alice"
# "Carol"

# Filter by string equality
echo '[{"name":"Alice","role":"admin"},{"name":"Bob","role":"user"}]' \
  | jq '.[] | select(.role == "admin") | .name'
# Output: "Alice"

การสร้างออบเจ็กต์และอาร์เรย์ขึ้นใหม่ด้วย {} และ []

jq ช่วยปรับรูปทรงข้อมูลได้ด้วยการสร้างออบเจ็กต์ใหม่ด้วย {} และอาร์เรย์ใหม่ด้วย []

  • {name: .name, city: .address.city} — เลือกและเปลี่ยนชื่อฟิลด์ลงในออบเจ็กต์ใหม่
  • [.items[] | .id] — รวบรวมค่าที่วนซ้ำกลับมาเป็นอาร์เรย์
  • รูปแบบย่อ: {name, age} เทียบเท่ากับ {name: .name, age: .age}

การครอบไปป์ไลน์ด้วย [...] เรียกว่าการสร้างอาร์เรย์ และจำเป็นเมื่อคุณต้องการผลลัพธ์เป็นอาร์เรย์ JSON แทนที่จะเป็นกระแสของค่า

# Reshape: keep only selected fields
echo '[{"id":1,"name":"Alice","password":"secret"},{"id":2,"name":"Bob","password":"secret"}]' \
  | jq '[.[] | {id, name}]'
# Output:
# [
#   {"id": 1, "name": "Alice"},
#   {"id": 2, "name": "Bob"}
# ]

# Collect filtered names into an array
echo '[{"name":"Alice","active":true},{"name":"Bob","active":false}]' \
  | jq '[.[] | select(.active) | .name]'
# Output: ["Alice"]

การทำงานกับอาร์เรย์ซ้อนกันและการไล่สำรวจแบบเวียนเกิด

JSON ในการใช้งานจริงมักซ้อนกันหลายชั้น jq มีเครื่องมือสองอย่างสำหรับการนำทางเชิงลึก:

  • .a.b.c — เส้นทางที่ระบุชัดเจนเมื่อทราบโครงสร้าง
  • .. | .fieldName? — การไล่สำรวจแบบเวียนเกิด: เดินผ่านทุกโหนดในต้นไม้และส่งออกค่าที่มีคีย์ดังกล่าวอยู่

ตัวดำเนินการ ? (ลองทำ) จะระงับข้อผิดพลาดเมื่อไม่มีฟิลด์อยู่ที่โหนดนั้น ซึ่งสำคัญอย่างยิ่งเมื่อใช้การไล่สำรวจแบบเวียนเกิดกับต้นไม้ที่มีโครงสร้างหลากหลาย

ใช้การไล่สำรวจแบบเวียนเกิดกับเอกสารขนาดใหญ่อย่างประหยัด เพราะจะเยี่ยมชมทุกโหนดและอาจทำงานช้า หากโครงสร้างคาดเดาได้ ควรเลือกใช้เส้นทางที่ระบุชัดเจน

# Explicit deep path
echo '{"a":{"b":{"c":42}}}' | jq '.a.b.c'
# Output: 42

# Recursive descent: find all "id" values anywhere in the tree
echo '{"users":[{"id":1,"profile":{"id":99}},{"id":2}]}' \
  | jq '.. | .id?'
# Output:
# 1
# 99
# 2

ตัวอย่างเชิงปฏิบัติ: การแยกวิเคราะห์การตอบกลับ API จาก curl

กรณีใช้งาน jq ที่พบบ่อยที่สุดอย่างหนึ่งคือการแยกวิเคราะห์การตอบกลับ REST API ที่ดึงมาด้วย curl การใช้ curl -s (ทำงานแบบเงียบ) ร่วมกับไปป์ไลน์ jq ช่วยให้ดึงข้อมูลได้สะอาดและนำไปใช้ในสคริปต์ได้

  • ดึงค่าหนึ่งค่า: curl -s URL | jq '.field'
  • สร้างตารางสรุป: วนซ้ำอาร์เรย์ แล้วสร้างออบเจ็กต์ใหม่โดยเก็บไว้เฉพาะฟิลด์ที่ต้องการ
  • ใช้ -r (ผลลัพธ์ดิบ) เพื่อลบเครื่องหมายอัญประกาศที่ครอบค่าสตริงออก ซึ่งจำเป็นเมื่อกำหนดค่าให้ตัวแปรเชลล์

เคล็ดลับ: เพิ่ม -r เสมอเมื่อจะนำผลลัพธ์จาก jq ไปใช้เป็นตัวแปรเชลล์หรือส่งต่อให้คำสั่งอื่น

#!/usr/bin/env bash
# Fetch GitHub repo info and extract specific fields
REPO="torvalds/linux"
RESPONSE=$(curl -s "https://api.github.com/repos/${REPO}")

# Extract fields
STARS=$(echo "$RESPONSE" | jq -r '.stargazers_count')
LANG=$(echo  "$RESPONSE" | jq -r '.language')
DESC=$(echo  "$RESPONSE" | jq -r '.description')

echo "Stars : $STARS"
echo "Lang  : $LANG"
echo "Desc  : $DESC"

การใช้ map() และ map_values()

jq มีฟังก์ชันลำดับสูงที่สะดวกสองอย่างสำหรับแปลงคอลเลกชัน:

  • map(f) — ใช้ตัวกรอง f กับสมาชิกทุกตัวของอาร์เรย์ แล้วคืนค่าเป็นอาร์เรย์ใหม่ เทียบเท่ากับ [.[] | f]
  • map_values(f) — ใช้ f กับค่าทุกค่าในออบเจ็กต์หรืออาร์เรย์ โดยคงคีย์หรือดัชนีไว้

ฟังก์ชันเหล่านี้อ่านเข้าใจง่ายกว่าการครอบไปป์ไลน์ด้วย [] ด้วยตนเอง และเป็นรูปแบบ jq ที่เหมาะสำหรับการแปลงข้อมูลซึ่งควรคงรูปเป็นอาร์เรย์

# map: extract a field from each element
echo '[{"name":"Alice","score":95},{"name":"Bob","score":80}]' \
  | jq 'map(.name)'
# Output: ["Alice", "Bob"]

# map with select: filter + transform in one step
echo '[{"name":"Alice","score":95},{"name":"Bob","score":60}]' \
  | jq 'map(select(.score >= 70) | .name)'
# Output: ["Alice"]

# map_values: multiply every value in an object by 2
echo '{"a":1,"b":2,"c":3}' | jq 'map_values(. * 2)'
# Output: {"a":2,"b":4,"c":6}

การจัดการฟิลด์ที่อาจมีหรือไม่มีก็ได้และค่าเริ่มต้นด้วย //

ข้อมูล JSON จากแหล่งภายนอกมักไม่สม่ำเสมอ ฟิลด์อาจหายไปหรือมีค่า null jq มีตัวดำเนินการทางเลือก // (เครื่องหมายทับสองตัว) เพื่อกำหนดค่าเริ่มต้น

  • .nickname // "anonymous" — ใช้ .nickname หากไม่ใช่ null หรือ false มิฉะนั้นใช้ "anonymous"
  • .count // 0 — ค่าเริ่มต้นเชิงตัวเลข
  • ใช้ร่วมกับ select: select((.status // "inactive") == "active")

วิธีนี้กระชับกว่าวิธีเทียบเท่าในเชลล์อย่าง ${VAR:-default} มาก และนำไปประกอบใช้ภายในไปป์ไลน์ที่ยาวขึ้นได้อย่างราบรื่น

# Provide defaults for missing/null fields
echo '[{"name":"Alice","role":"admin"},{"name":"Bob"}]' \
  | jq '[.[] | {name, role: (.role // "user")}]'
# Output:
# [
#   {"name": "Alice", "role": "admin"},
#   {"name": "Bob",   "role": "user"}
# ]

# Numeric default
echo '{"items":[1,2,3]}' | jq '.total // 0'
# Output: 0

สคริปต์เชิงปฏิบัติ: ตัวแยกวิเคราะห์บันทึก JSON

การบันทึกข้อมูลในรูปแบบ JSON ที่มีโครงสร้างเป็นมาตรฐานของระบบสมัยใหม่ ต่อไปนี้คือสคริปต์ที่ใช้งานได้จริง โดยอ่านไฟล์บันทึก JSON ที่แบ่งบรรทัดละหนึ่งรายการ กรองรายการที่เป็นข้อผิดพลาด และจัดรูปแบบเป็นสรุปที่มนุษย์อ่านได้

รูปแบบสำคัญที่ใช้:

  • -c (ผลลัพธ์แบบกระชับ) — หนึ่งออบเจ็กต์ JSON ต่อบรรทัด เหมาะสำหรับส่งต่อให้ลูปของเชลล์
  • --arg name value — แทรกตัวแปรเชลล์เป็นอาร์กิวเมนต์สตริงของ jq
  • select สำหรับกรองตามระดับของบันทึก
  • -r สำหรับผลลัพธ์สตริงดิบที่เหมาะกับ echo
#!/usr/bin/env bash
# Parse newline-delimited JSON logs and report ERRORs
# Each log line: {"level":"ERROR","msg":"...","ts":"2024-01-15T10:23:00Z","svc":"auth"}

LOG_FILE="/var/log/app/app.log"
LEVEL="ERROR"

echo "=== $LEVEL entries in $LOG_FILE ==="

jq -r --arg lvl "$LEVEL" \
  'select(.level == $lvl) | "[\(.ts)] [\(.svc)] \(.msg)"' \
  "$LOG_FILE"

# Count errors per service
echo ""
echo "=== Error count by service ==="
jq -r --arg lvl "$LEVEL" \
  'select(.level == $lvl) | .svc' "$LOG_FILE" \
  | sort | uniq -c | sort -rn

ตรวจสอบความเข้าใจ: พฤติกรรมของ select() ใน jq

ทดสอบความเข้าใจเกี่ยวกับการทำงานของ select() ภายในกระบวนการต่อเนื่องของ jq

กำหนดให้มีคำสั่งต่อไปนี้:

echo '[{"name":"Alice","age":30},{"name":"Bob","age":17},{"name":"Carol","age":22}]' | jq '[.[] | select(.age >= 18) | .name]'

ผลลัพธ์จะเป็นอย่างไร

สรุปบทเรียน: กระบวนการต่อเนื่องของ jq สำหรับกรอง JSON

คุณได้เรียนรู้เครื่องมือหลักของ jq สำหรับนำทางและกรอง JSON จากบรรทัดคำสั่งแล้ว:

  • สัญกรณ์จุด (.field, .a.b.c) ใช้เลือกฟิลด์จากออบเจ็กต์
  • การเข้าถึงอาร์เรย์ (.[0], .[]) ใช้ระบุดัชนีและวนซ้ำผ่านอาร์เรย์
  • ตัวดำเนินการไปป์ (|) ใช้เชื่อมตัวกรองเข้าด้วยกัน โดยแต่ละขั้นตอนจะประมวลผลค่าทั้งหมดจากขั้นตอนก่อนหน้า
  • select(cond) ใช้กรองค่า โดยส่งต่อเฉพาะค่าที่เงื่อนไขเป็นจริง
  • การสร้างออบเจ็กต์/อาร์เรย์ ({}, [], map()) ใช้ปรับรูปข้อมูลให้เป็นโครงสร้างใหม่
  • ตัวดำเนินการทางเลือก (//) ใช้กำหนดค่าเริ่มต้นให้ฟิลด์ที่เป็นค่าว่างหรือไม่มีอยู่
  • แฟล็ก -r ใช้ตัดเครื่องหมายคำพูดสำหรับกำหนดค่าให้ตัวแปรเชลล์ ส่วน --arg ใช้แทรกตัวแปรเชลล์อย่างปลอดภัย
  • การไล่สำรวจแบบเรียกซ้ำ (.. | .field?) ใช้ค้นหาในโครงสร้างต้นไม้ที่ซ้อนกันลึก เมื่อไม่ทราบเส้นทาง

ด้วยองค์ประกอบเหล่านี้ คุณสามารถแปลงการตอบกลับจาก API ที่เป็น JSON ไฟล์บันทึก หรือการกำหนดค่า ให้เป็นข้อมูลตรงตามที่สคริปต์ต้องการได้ โดยไม่ต้องออกจากเทอร์มินัล

คำถามที่พบบ่อย

บทเรียน “การกรองและเลือก JSON ด้วยไปป์ไลน์ jq” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การกรองและเลือก JSON ด้วยไปป์ไลน์ jq” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Linux Command Line & Bash Scripting Mastery ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การกรองและเลือก JSON ด้วยไปป์ไลน์ jq”

เข้าถึงออบเจกต์ซ้อนกันและอาร์เรย์ด้วยตัวเลือก ท่อ และตัวกรอง select ของ jq คุณปฏิบัติ Linux Command Line & Bash Scripting Mastery ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Linux Command Line & Bash Scripting Mastery หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Linux Command Line & Bash Scripting Mastery บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “การกรองและเลือก JSON ด้วยไปป์ไลน์ jq” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Linux Command Line & Bash Scripting Mastery นี้ได้ไหม

ได้ บทเรียน Linux Command Line & Bash Scripting Mastery ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การกรองและเลือก JSON ด้วยไปป์ไลน์ jq
  2. การแปลงและสร้างออบเจกต์ JSON ด้วย jq
  3. การใช้ REST API ด้วย curl และ jq ร่วมกัน
  4. การแก้ไขไฟล์การกำหนดค่า YAML ด้วย yq
← กลับไปที่ Linux Command Line & Bash Scripting Mastery