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

การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk

คำนวณผลรวม จำนวน และสรุปแบบจัดกลุ่มด้วยอาร์เรย์เชิงเชื่อมโยงที่ใช้ค่าฟิลด์เป็นกุญแจ

บทเรียน 3 จาก 413 ขั้นตอน

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

อาร์เรย์แบบเชื่อมโยงของ awk คืออะไร

ใน awk อาร์เรย์แบบเชื่อมโยงคือที่เก็บข้อมูลแบบคีย์-ค่า ซึ่งคีย์สามารถเป็นสตริงหรือตัวเลขใดก็ได้ ต่างจากอาร์เรย์แบบมีดัชนีในภาษาส่วนใหญ่ ภายในแล้วอาร์เรย์ของ awk เป็น แผนผังแฮช จึงเหมาะอย่างยิ่งสำหรับการจัดกลุ่มและรวมข้อมูลตามค่าของฟิลด์

  • ประกาศโดยปริยาย: เพียงกำหนดค่า arr[key] = value
  • โดยค่าเริ่มต้นคีย์เป็นสตริง (ตัวเลขจะถูกแปลงชนิด)
  • ไม่มีขีดจำกัดขนาด — awk จะขยายอาร์เรย์ตามความจำเป็น
  • เหมาะสำหรับการคำนวณผลรวม จำนวนครั้ง และผลรวมแยกตามกลุ่มในการอ่านข้อมูลเพียงรอบเดียว

คุณไม่จำเป็นต้องกำหนดค่าเริ่มต้นให้คีย์ก่อนเพิ่มค่า — awk จะถือว่าคีย์ที่ยังไม่ได้กำหนดมีค่าเป็นศูนย์หรือสตริงว่างโดยอัตโนมัติ

การนับจำนวนบรรทัดแยกตามกลุ่ม

รูปแบบการรวมข้อมูลที่ใช้กันมากที่สุดคือการนับว่าค่าไม่ซ้ำกันแต่ละค่าในฟิลด์ปรากฏกี่ครั้ง ใช้ฟิลด์ $1 (หรือฟิลด์ใดก็ได้) เป็นคีย์ของอาร์เรย์ แล้วเพิ่มตัวนับในทุกแถวที่ตรงกัน

บล็อก END จะทำงานหลังจากอ่านข้อมูลเข้าทั้งหมดแล้ว — จึงเป็นตำแหน่งที่ใช้พิมพ์ผลลัพธ์ที่สะสมไว้

count[$1]++

หลังประมวลผลแล้ว count จะเก็บจำนวนบรรทัดทั้งหมดของค่าไม่ซ้ำกันแต่ละค่าของ $1

#!/usr/bin/env bash
# Count how many log entries exist per HTTP status code
# Input format: <ip> <date> <method> <path> <status> <bytes>
printf '10.0.0.1 2024-01-01 GET /index 200 512
10.0.0.2 2024-01-01 POST /api 404 128
10.0.0.3 2024-01-01 GET /img 200 2048
10.0.0.4 2024-01-01 GET /api 500 64
10.0.0.5 2024-01-01 DELETE /api 404 32
' | awk '
{
    count[$5]++
}
END {
    for (status in count)
        print status, count[status]
}'

การหาผลรวมฟิลด์ตัวเลขแยกตามกลุ่ม

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

รูปแบบคือ:

  • คีย์ = ฟิลด์ที่ใช้จัดกลุ่ม (เช่น $1 สำหรับชื่อผู้ใช้)
  • ค่า = ผลรวมสะสมของฟิลด์ตัวเลข (เช่น $2 สำหรับจำนวนไบต์)

วิธีนี้คำนวณผลรวมแยกตามกลุ่มได้ครบถ้วนในการอ่านข้อมูลด้วย awk เพียงรอบเดียว — ไม่จำเป็นต้องเรียงลำดับหรือประมวลผลล่วงหน้า

#!/usr/bin/env bash
# Sum bytes transferred per user from an access log
printf 'alice 1024
bob 512
alice 2048
charlie 256
bob 768
alice 128
' | awk '
{
    bytes[$1] += $2
}
END {
    for (user in bytes)
        printf "%-10s %d bytes\n", user, bytes[user]
}'

การรวมจำนวนและผลรวมในการอ่านข้อมูลรอบเดียว

awk ช่วยให้คุณดูแลรักษาอาร์เรย์หลายชุดพร้อมกันได้ ทำให้ได้ทั้งจำนวนและผลรวม (และจึงคำนวณค่าเฉลี่ยได้) ของแต่ละกลุ่มในการอ่านไฟล์เพียงรอบเดียว ซึ่งมีประสิทธิภาพมากกว่าการเรียกใช้กระบวนการส่งต่อคำสั่งสองครั้ง

  • count[key]++ — ติดตามจำนวนครั้งที่ปรากฏ
  • total[key] += $N — ติดตามผลรวมสะสม
  • ใน END ให้หาร total[k] / count[k] เพื่อหาค่าเฉลี่ยของแต่ละกลุ่ม
#!/usr/bin/env bash
# Compute per-department headcount and average salary
printf 'Engineering Alice 95000
Engineering Bob 88000
Marketing Carol 72000
Marketing Dave 68000
Engineering Eve 102000
Marketing Frank 75000
' | awk '
{
    dept  = $1
    sal   = $3
    count[dept]++
    total[dept] += sal
}
END {
    printf "%-15s %5s %10s\n", "Department", "Count", "Avg Salary"
    for (d in count)
        printf "%-15s %5d %10.0f\n", d, count[d], total[d]/count[d]
}'

คีย์จากหลายฟิลด์สำหรับการจัดกลุ่มสองมิติ

คุณสามารถสร้างคีย์ผสมได้โดยนำหลายฟิลด์มาต่อกันด้วยตัวคั่น วิธีนี้ทำให้จัดกลุ่มแบบสองมิติได้โดยไม่ต้องใช้ไวยากรณ์พิเศษ

เลือกตัวคั่นที่ไม่สามารถปรากฏในข้อมูลได้ (เช่น SUBSEP ซึ่งเป็นตัวคั่นระเบียนในตัวของ awk คือ \034 หรือตัวขีดตั้ง | แบบเขียนตรง ๆ)

  • คีย์ผสม: arr[$1 SUBSEP $2] หรือ arr[$1"|"$2]
  • แยกคีย์กลับเมื่อพิมพ์ผลลัพธ์: split(key, parts, "|")
#!/usr/bin/env bash
# Count requests grouped by HTTP method AND status code
printf 'GET 200
POST 201
GET 404
GET 200
DELETE 204
POST 201
GET 404
POST 500
' | awk '
{
    key = $1 "|" $2
    count[key]++
}
END {
    printf "%-8s %-6s %s\n", "Method", "Status", "Count"
    for (k in count) {
        split(k, parts, "|")
        printf "%-8s %-6s %d\n", parts[1], parts[2], count[k]
    }
}'

การติดตามค่าต่ำสุดและค่าสูงสุดแยกตามกลุ่ม

อาร์เรย์แบบเชื่อมโยงทำให้ติดตามค่าต่ำสุดและสูงสุดแยกตามกลุ่มได้ง่าย เคล็ดลับคือกำหนดค่าเริ่มต้นเฉพาะเมื่อพบคีย์นั้นเป็นครั้งแรก โดยใช้เงื่อนไขพิเศษ !(key in arr)

  • !(key in min_arr) เป็นจริงเมื่อพบคีย์เป็นครั้งแรก
  • หลังจากกำหนดค่าเริ่มต้นแล้ว ให้เปรียบเทียบและเขียนทับด้วยการตรวจสอบน้อยกว่า / มากกว่าแบบมาตรฐาน

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

#!/usr/bin/env bash
# Find min and max response time per endpoint
printf '/api/users 120
/api/orders 340
/api/users 98
/api/orders 512
/api/users 210
/api/orders 280
/health 5
/health 7
' | awk '
{
    ep  = $1
    rt  = $2
    if (!(ep in mn)) { mn[ep] = rt; mx[ep] = rt }
    if (rt < mn[ep]) mn[ep] = rt
    if (rt > mx[ep]) mx[ep] = rt
}
END {
    printf "%-15s %6s %6s\n", "Endpoint", "Min", "Max"
    for (ep in mn)
        printf "%-15s %6d %6d\n", ep, mn[ep], mx[ep]
}'

การแจกแจงความถี่ — กลุ่ม N อันดับแรก

งานที่พบได้บ่อยในโลกจริงคือการค้นหาค่าที่ปรากฏบ่อยที่สุด N อันดับแรก awk จะจัดการนับจำนวน จากนั้นส่งต่อผ่าน sort และ head เพื่อจัดอันดับและตัดผลลัพธ์

รูปแบบกระบวนการส่งต่อคำสั่งนี้เป็นแนวทางตามแบบแผนในการเขียนโปรแกรมเชลล์:

  1. awk นับจำนวนครั้งที่ปรากฏลงในอาร์เรย์ แล้วพิมพ์ count key ใน END
  2. sort -rn เรียงลำดับตัวเลขจากมากไปน้อย
  3. head -n 5 เก็บไว้เฉพาะ 5 อันดับแรก

การให้ awk มุ่งเน้นที่การรวมข้อมูล และมอบหมายการเรียงลำดับให้ sort สอดคล้องกับปรัชญา Unix

#!/usr/bin/env bash
# Top 3 most active IP addresses from an access log
printf '192.168.1.10 GET /index
10.0.0.5 POST /api
192.168.1.10 GET /css
172.16.0.3 GET /index
10.0.0.5 GET /api
192.168.1.10 DELETE /api
172.16.0.3 POST /login
10.0.0.5 GET /index
10.0.0.5 POST /logout
' | awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' \
  | sort -rn \
  | head -n 3

การใช้ NR และ FNR เพื่อรวมข้อมูลจากหลายไฟล์

เมื่อประมวลผลหลายไฟล์ ค่าในตัวของ awk อย่าง NR (จำนวนระเบียนที่อ่านทั้งหมด) และ FNR (จำนวนระเบียนในไฟล์ปัจจุบัน) ช่วยให้คุณระบุได้ว่าแต่ละระเบียนมาจากไฟล์ใดโดยใช้ FILENAME

  • FILENAME — ชื่อไฟล์ที่กำลังอ่านอยู่
  • FNR == 1 — ทำงานเมื่อเริ่มไฟล์ใหม่แต่ละไฟล์ (มีประโยชน์สำหรับข้ามส่วนหัว)

วิธีนี้ทำให้รวมข้อมูลแยกตามกลุ่มของแต่ละไฟล์ได้ทั่วทั้งไดเรกทอรีที่มีบันทึกการทำงาน โดยเรียกใช้ awk เพียงครั้งเดียว

การพิมพ์ผลลัพธ์ที่เรียงลำดับจากอาร์เรย์ของ awk

ลูป for (key in array) ใน awk ไม่รับประกันลำดับ หากต้องการผลลัพธ์ที่แน่นอน ให้ส่งผลลัพธ์จากการพิมพ์ใน END ของ awk ไปยัง sort หรือรวบรวมค่าแล้วเรียงลำดับภายใน awk โดยใช้ฟังก์ชัน asorti / asort (ใช้ได้เฉพาะ GNU awk)

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

  • sort -k1,1 — เรียงตามฟิลด์แรก (คีย์กลุ่ม) ตามตัวอักษร
  • sort -k2,2rn — เรียงตามฟิลด์ที่สอง (จำนวน/ผลรวม) เป็นตัวเลขจากมากไปน้อย
#!/usr/bin/env bash
# Bytes per user, sorted alphabetically by username
printf 'zara 800
alice 1500
bob 300
alice 200
zara 400
bob 1100
' | awk '
{
    total[$1] += $2
}
END {
    for (u in total)
        print u, total[u]
}' | sort -k1,1

การลบคีย์ของอาร์เรย์และการล้างสถานะ

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

  • delete arr[key] — ลบรายการเดียว
  • delete arr — ล้างอาร์เรย์ทั้งหมด (GNU awk)
  • ตรวจสอบการมีอยู่ด้วย (key in arr) ก่อนเข้าถึง เพื่อหลีกเลี่ยงการสร้างรายการหลอก

เทคนิคนี้ช่วยให้รวมข้อมูลแบบหน้าต่างเลื่อนหรือแยกตามส่วนได้โดยไม่ต้องเริ่ม awk ใหม่

#!/usr/bin/env bash
# Sum values within each section delimited by "---"
printf 'alice 100
bob 200
---
alice 50
bob 75
charlie 300
---
' | awk '
/^---/ {
    print "-- Section totals --"
    for (u in total) printf "  %-10s %d\n", u, total[u]
    delete total
    next
}
{
    total[$1] += $2
}'

กระบวนการส่งต่อคำสั่งในโลกจริง: สรุปบันทึกการทำงานของ Nginx

เมื่อนำทุกอย่างมารวมกัน — ต่อไปนี้คือการรวมข้อมูลด้วย awk ในการอ่านข้อมูลจากรูปแบบบันทึกแบบผสมของ Nginx ระดับพร้อมใช้งานจริง โดยอ่านข้อมูลเพียงรอบเดียว การทำงานนี้คำนวณจำนวนคำขอ จำนวนไบต์ทั้งหมด และอัตราข้อผิดพลาดแยกตามโฮสต์เสมือน

เทคนิคสำคัญที่ใช้:

  • คีย์ผสม: vhost ที่ดึงมาจากฟิลด์หนึ่ง
  • อาร์เรย์แบบขนาน: reqs[], bytes[], errors[]
  • การสะสมแบบมีเงื่อนไข: $9 >= 400 เพื่อนับเฉพาะการตอบกลับที่เป็นข้อผิดพลาด
  • ตาราง printf ที่จัดรูปแบบใน END
#!/usr/bin/env bash
# Simulated Nginx combined log: host ip - - [date] "METHOD /path HTTP/1.1" status bytes
printf 'api.example.com 10.0.0.1 - - [01/Jan/2024] "GET /v1" 200 1024
www.example.com 10.0.0.2 - - [01/Jan/2024] "GET /" 200 4096
api.example.com 10.0.0.3 - - [01/Jan/2024] "POST /v1" 500 128
www.example.com 10.0.0.4 - - [01/Jan/2024] "GET /img" 404 64
api.example.com 10.0.0.5 - - [01/Jan/2024] "GET /v1" 200 2048
www.example.com 10.0.0.6 - - [01/Jan/2024] "GET /" 200 4096
api.example.com 10.0.0.7 - - [01/Jan/2024] "DELETE /v1" 403 32
' | awk '
{
    host = $1; status = $9; b = $10
    reqs[host]++
    bytes[host] += b
    if (status + 0 >= 400) errors[host]++
}
END {
    printf "%-20s %6s %10s %6s\n", "Host", "Reqs", "Bytes", "Errors"
    for (h in reqs)
        printf "%-20s %6d %10d %6d\n", h, reqs[h], bytes[h], errors[h]+0
}'

ตรวจสอบความรู้: การกำหนดค่าต่ำสุดเริ่มต้นอย่างถูกต้อง

ทดสอบความเข้าใจของคุณเกี่ยวกับข้อผิดพลาดที่พบบ่อยในการรวมข้อมูลด้วย awk

สรุปบทเรียน: การรวมข้อมูลด้วยอาร์เรย์ของ awk

คุณได้เรียนรู้รูปแบบหลักสำหรับคำนวณการรวมข้อมูลแยกตามกลุ่มทั้งหมดภายใน awk แล้ว:

  • การนับ: count[$key]++ — เพิ่มค่าในแต่ละแถว แล้วพิมพ์ใน END
  • การหาผลรวม: total[$key] += $N — สะสมฟิลด์ตัวเลขแยกตามกลุ่ม
  • ค่าเฉลี่ย: ดูแลทั้ง count[] และ total[] แล้วหารใน END
  • ค่าต่ำสุด/สูงสุด: กำหนดค่าเริ่มต้นเมื่อพบครั้งแรกโดยใช้ !(key in arr) จากนั้นจึงเปรียบเทียบ
  • คีย์ผสม: ต่อฟิลด์เข้าด้วยกันด้วยตัวคั่นเพื่อจัดกลุ่มหลายมิติ
  • ผลลัพธ์ที่เรียงลำดับ: ส่งผลลัพธ์จากการพิมพ์ใน END ของ awk ไปยัง sort เพื่อให้ลำดับแน่นอน
  • การรีเซ็ตส่วน: ใช้ delete arr เพื่อล้างสถานะระหว่างส่วนตรรกะต่าง ๆ ของข้อมูลเข้า

รูปแบบเหล่านี้ช่วยให้คุณแทนที่คำสั่งค้นหาฐานข้อมูลที่ซับซ้อนหรือการประมวลผลผ่านกระบวนการส่งต่อคำสั่งหลายรอบด้วยการเรียกใช้ awk เพียงครั้งเดียวอย่างมีประสิทธิภาพ ซึ่งเป็นทักษะสำคัญสำหรับการเขียนโปรแกรมเชลล์ในระบบใช้งานจริง

เริ่มต้นได้ฟรี

เรียนรู้ Bash ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
22
บทเรียน
88

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

บทเรียน “การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk”

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

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

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

บทเรียน “การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk” ใช้เวลานานแค่ไหน

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

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

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

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

  1. ระเบียน ฟิลด์ และตัวคั่นแบบกำหนดเองใน awk
  2. รูปแบบ ช่วง และบล็อก BEGIN/END
  3. การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk
  4. ฟังก์ชัน awk การจัดรูปแบบด้วย printf และการสร้างรายงาน
← กลับไปที่ Linux Command Line & Bash Scripting Mastery