จัดเรียงไฟล์ข้อความที่มีหลายบรรทัดเป็นแถว


14

ฉันมีไฟล์ข้อความในรูปแบบนี้:

####################################
KEY2
VAL21
VAL22
VAL23
VAL24
####################################
KEY1
VAL11
VAL12
VAL13
VAL14
####################################
KEY3
VAL31
VAL32
VAL33
VAL34

ฉันต้องการเรียงลำดับไฟล์นี้ตามKEYบรรทัดและเก็บ 4 บรรทัดถัดไปไว้ในผลลัพธ์ดังนั้นผลลัพธ์ที่เรียงควรเป็น:

####################################
KEY1
VAL11
VAL12
VAL13
VAL14
####################################
KEY2
VAL21
VAL22
VAL23
VAL24
####################################
KEY3
VAL31
VAL32
VAL33
VAL34

มีวิธีทำเช่นนี้หรือไม่?


5
ไม่ได้โพสต์ข้ามโปรด
Zanna

@ ซานน่า: ฉันคิดว่ามีการยกเว้นสำหรับส่วน unix และ askubuntu เพราะทั้งสองมีทับซ้อนกันมากกับแต่ละคน! ฉันคิดว่าฉันอ่านเกี่ยวกับเรื่องนี้ในส่วนของเมตาของยูนิกซ์
RYN

2
คำถามเมตาที่เกี่ยวข้องถามโดย mod mod ที่นี่ :) คำถามที่ควรโพสต์ในการถาม Ubuntu ได้รับการจัดการอย่างไร
Zanna

@RYN ปัญหาไม่ได้เกิดจากการซ้อนทับกันจริง ๆ แล้วไซต์ SE มีจำนวนมากทับซ้อนกัน แต่คนที่ให้คำตอบอาจไม่รู้เกี่ยวกับคำตอบในเว็บไซต์อื่น
phk

คำตอบ:


13

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

AFAICT คุณไม่สามารถใช้รูปแบบโดยพลการสำหรับบันทึกได้ดังนั้นหากบันทึกของคุณมีขนาดคงที่ (เป็นไบต์ไม่ใช่อักขระหรือบรรทัด) msortไม่มี-bตัวเลือกสำหรับระเบียนที่เป็นบล็อกของบรรทัดคั่นด้วยบรรทัดว่าง

คุณสามารถแปลงอินพุตของคุณเป็นรูปแบบที่จะทำงาน-bได้อย่างง่ายดายโดยใส่บรรทัดว่างไว้ข้างหน้าทุกอัน###...(ยกเว้นอันแรก)

ตามค่าเริ่มต้นจะพิมพ์สถิติบน stderr ดังนั้นอย่างน้อยก็ง่ายที่จะบอกเมื่อไม่ได้เรียงลำดับเพราะคิดว่าอินพุตทั้งหมดเป็นบันทึกเดียว


msortทำงานกับข้อมูลของคุณ sedคำสั่ง prepends ขึ้นบรรทัดใหม่ให้ทุก#+สายยกเว้นสาย 1. -wเรียงลำดับระเบียนทั้งหมด (lexicographically) มีตัวเลือกสำหรับเลือกส่วนของระเบียนที่จะใช้เป็นคีย์ แต่ฉันไม่ต้องการ

ฉันยังทิ้งการขึ้นบรรทัดใหม่พิเศษ

$ sed '2,$ s/^#\+/\n&/' unsorted.records | msort -b -w 2>/dev/null 
####################################
KEY1
VAL11
VAL12
VAL13
VAL14

####################################
KEY2
VAL21
VAL22
VAL23
VAL24

####################################
KEY3
VAL31
VAL32
VAL33
VAL34

ฉันไม่มีโชคกับ-r '#'การใช้สิ่งนั้นเป็นตัวแยกเร็กคอร์ด มันคิดว่าไฟล์ทั้งหมดเป็นหนึ่งระเบียน


ขอบคุณมาก; msortมีประโยชน์มาก ขอบคุณ ( -rดูเหมือนว่ามันเป็นเพราะมีมากกว่าหนึ่ง # ฉันใช้-dและใช้งานได้
RYN

เย็น! (+1) ใช้msort -qwr '#' ex งานได้สำหรับฉัน (เช่นกันมันเป็นการแยกตัวคั่นเอาต์พุตเอาท์พุท)
JJoao

9

วิธีแก้ไขคือการเปลี่ยนบรรทัดฟีดภายในบล็อกเป็นอักขระที่ไม่ได้ใช้ที่คุณเลือก ('|' ในตัวอย่างด้านล่าง) เพื่อเรียงลำดับผลลัพธ์และเปลี่ยนตัวคั่นที่เลือกเป็นฟีดบรรทัดเดิม:

sed -e 'N; N; N; N; N; s/\n/|/g' file.txt \
| sort -k2,2 -t\| \
| sed 's/|/\n/g'

1
ขอบคุณ; ใช้งานได้ แต่มันสกปรกมากเป็นพิเศษเมื่อข้อมูลสกปรกเกินไป! ถ้าเส้นหลังคีย์คือ 100 ฉันต้องใส่ 100 ;Nตรงนั้นและมันอาจยากที่จะหาตัวละครที่ไม่ได้ใช้ในข้อความตัวเอง มันดีมากสำหรับsortหรือawk... สามารถทำการคัดแยกหลายสายได้
RYN

5
perl -0ne 'print sort /(#+[^#]*)/g' file.txt
  • perl -0 slurps ไฟล์ทั้งหมด
  • /(....)/g จับคู่และแยกข้อมูล
  • print sort ... จัดเรียงและพิมพ์พวกเขา

2

นี่เป็นอีกวิธีหนึ่งที่ควรใช้กับจำนวนบรรทัดในKEYส่วนใดก็ได้:

# extract delimiter
delim=$(head -n1 <infile)
sed '/#/d;/KEY/h;G;s/\n/\x02/' infile | nl -ba -nrz -s $'\002' | sort -t $'\002' -k3 -k1,1 |
cut -d $'\002' -f2 | sed '/KEY/{x;s/.*/'"${delim}"'/;G}'

สิ่งนี้ทำงานได้โดยการบันทึกตัวคั่นลงในตัวแปร (เพื่อลบออกจากอินพุต) จากนั้นก็ผนวกKEY*กับแต่ละบรรทัดในส่วนที่สอดคล้องกันของการใช้ถ่านต่ำ ASCII (ซึ่งไม่น่าจะเกิดขึ้นในการป้อนข้อมูลของคุณ) เป็นตัวคั่นแล้วnumbers ทั้งหมดlInes ใช้คั่นเดียวกัน มันแล้วเท่านั้นเรื่องของsortไอเอ็นจีโดยครั้งที่ 3 และครั้งที่ 1 สนามและการใช้งานคอลัมน์กลางและจากนั้นการเรียกคืนตัวคั่นผ่านเป็นครั้งสุดท้ายcut sedโปรดทราบว่าด้วยการข้างต้นKEY12จะเรียงลำดับก่อนKEY2ดังนั้นปรับsortคำสั่งตามความต้องการของคุณ


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.