การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk
คำนวณผลรวม จำนวน และสรุปแบบจัดกลุ่มด้วยอาร์เรย์เชิงเชื่อมโยงที่ใช้ค่าฟิลด์เป็นกุญแจ
การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk เป็นบทเรียน DevOps Bootcamp ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน DevOps Bootcamp และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส DevOps Bootcamp มีบทเรียนทั้งหมด 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 เพื่อจัดอันดับและตัดผลลัพธ์
รูปแบบกระบวนการส่งต่อคำสั่งนี้เป็นแนวทางตามแบบแผนในการเขียนโปรแกรมเชลล์:
- awk นับจำนวนครั้งที่ปรากฏลงในอาร์เรย์ แล้วพิมพ์
count keyในEND sort -rnเรียงลำดับตัวเลขจากมากไปน้อย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 เพียงครั้งเดียวอย่างมีประสิทธิภาพ ซึ่งเป็นทักษะสำคัญสำหรับการเขียนโปรแกรมเชลล์ในระบบใช้งานจริง
คำถามที่พบบ่อย
บทเรียน “การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส DevOps Bootcamp ให้อัปเกรดเป็น CoddyKit PRO คอร์ส DevOps Bootcamp มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk”
คำนวณผลรวม จำนวน และสรุปแบบจัดกลุ่มด้วยอาร์เรย์เชิงเชื่อมโยงที่ใช้ค่าฟิลด์เป็นกุญแจ คุณปฏิบัติ DevOps Bootcamp ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน DevOps Bootcamp หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน DevOps Bootcamp บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน DevOps Bootcamp นี้ได้ไหม
ได้ บทเรียน DevOps Bootcamp ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ระเบียน ฟิลด์ และตัวคั่นแบบกำหนดเองใน awk
- รูปแบบ ช่วง และบล็อก BEGIN/END
- การรวมข้อมูลด้วยอาร์เรย์และการจัดกลุ่มใน awk
- ฟังก์ชัน awk การจัดรูปแบบด้วย printf และการสร้างรายงาน