การใช้ awk เพื่อรวมค่าของคอลัมน์ตามค่าของคอลัมน์อื่น


63

awkฉันพยายามที่จะสรุปตัวเลขบางอย่างในคอลัมน์โดยใช้ ฉันต้องการรวมเพียงคอลัมน์ 3 ของ "smiths" เพื่อรับรวม 212 ฉันสามารถรวมคอลัมน์ทั้งหมดโดยใช้awkแต่ไม่ใช่แค่ "smiths" ฉันมี:

awk 'BEGIN {FS = "|"} ; {sum+=$3} END {print sum}' filename.txt

นอกจากนี้ฉันกำลังใช้ผงสำหรับอุดรู ขอบคุณสำหรับความช่วยเหลือ

smiths|Login|2
olivert|Login|10
denniss|Payroll|100
smiths|Time|200
smiths|Logout|10

คำตอบ:


81
awk -F '|' '$1 ~ /smiths/ {sum += $3} END {print sum}' inputfilename
  • -Fธงชุดแยกทุ่งนา ฉันใส่ไว้ในเครื่องหมายคำพูดเดี่ยวเพราะมันเป็นอักขระพิเศษของเชลล์
  • จากนั้น$1 ~ /smiths/นำไปใช้ต่อไปนี้ {} ป้องกันรหัสเฉพาะกับสายที่ฟิลด์แรกตรงกับ /smiths/regex
  • ส่วนที่เหลือเหมือนกับรหัสของคุณ

โปรดทราบว่าเนื่องจากคุณไม่ได้ใช้ regex ที่นี่จริง ๆ มีเพียงค่าเฉพาะคุณจึงสามารถใช้:

awk -F '|' '$1 == "smiths" {sum += $3} END {print sum}' inputfilename

ซึ่งตรวจสอบความเท่าเทียมกันของสตริง นี่เทียบเท่ากับการใช้ regex /^smiths$/ดังที่กล่าวไว้ในคำตอบอื่นซึ่งรวมถึง^จุดยึดที่ตรงกับจุดเริ่มต้นของสตริงเท่านั้น (จุดเริ่มต้นของเขตข้อมูล 1) และ$จุดยึดจะตรงกับจุดสิ้นสุดของสตริงเท่านั้น ไม่แน่ใจว่าคุณคุ้นเคยกับ regexes อย่างไร มันมีประสิทธิภาพมาก แต่สำหรับกรณีนี้คุณสามารถใช้การตรวจสอบความเท่าเทียมกันของสตริงได้อย่างง่ายดาย


3
โดยวิธีการไปสู่การอ้างอิง awk ที่ชื่นชอบคือgrymoire.com/Unix/Awk.html หน้ามีประโยชน์มาก
Wildcard

1
ขอบคุณ @Wildcard! ผมสามารถที่จะรวมอย่างเรียบร้อยไม่มีการบีบอัดขนาดของไฟล์โดยเฉพาะอย่างยิ่งในการเก็บซิปขนาดใหญ่ขึ้นอยู่กับคำแนะนำของคุณ :) unzip -lv /appl/tmp/data.lar | grep documentlibrary | awk '{sum += $1} END {print sum/1024/1024}'
Pawel

15

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

awk -F '|' '{a[$1] += $3} END{print a["smiths"]}' filename.txt

ในฐานะที่เป็นผลข้างเคียงอาร์เรย์เก็บค่าอื่น ๆ ทั้งหมด:

awk -F '|' '{a[$1] += $3} END{for (i in a) print i, a[i]}' filename.txt

เอาท์พุท:

smiths 212
denniss 100
olivert 10

นี่คือคำตอบที่ถูกต้อง
PoVa

5

ดีมากจนถึงตอนนี้ สิ่งที่คุณต้องทำคือเพิ่มตัวเลือกก่อนบล็อกเพื่อเพิ่มผลรวม ที่นี่เราตรวจสอบว่าอาร์กิวเมนต์แรกมีเพียง "smiths":

awk 'BEGIN {FS = "|"} ; $1 ~ /^smiths$/ {sum+=$3} END {print sum}'

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

awk -F'|' '$1 ~ /^smiths$/ {sum+=$3} END {print sum}'

0
cat filename.txt | grep smiths | awk -F '|' '{sum+=$NF} END {print sum}'
  • -F ตัวเลือกเพื่อระบุตัวคั่น
  • $NF ใช้สำหรับ "คอลัมน์สุดท้าย"

1
catและgrepไม่จำเป็นที่นี่
Andrey

ทำไม grep จึงไม่จำเป็น @Andrey OP ต้องการเพิ่มแถว "smiths" เท่านั้น คุณต้องการแก้ไขคำสั่ง awk ใช่ไหม?
EL

1
@EL ใช่คำสั่ง awk ควรได้รับการแก้ไข/smiths/{...}หากการเรียก grep ไม่มีอยู่ นี่คือการปรับเปลี่ยนเล็กน้อย แต่ให้ประโยชน์ที่สำคัญ: ลดจำนวนกระบวนการทำงานลดความซับซ้อนของการควบคุมข้อผิดพลาดและทำให้รหัสชัดเจนขึ้น
Andrey

0

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

cat filename.txt | perl -pe 's{.*|}{}g' | awk '{sum+=$1} END {print sum}'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.