รวมสองไฟล์ด้วย awk


9

File1.txt

item1   carA
item2   carB
item3   carC
item4   platD
item5   carE

File2.txt

carA  platA
carB  platB
carC  platC
carE  platE

เอาท์พุทที่ต้องการ:

item1   platA
item2   platB
item3   platC
item4   platD
item5   platE

ฉันจะทำมันได้อย่างไร

คำตอบ:


11

คำตอบด้านล่างขึ้นอยู่กับคำถามและคำตอบที่คล้ายกันใน SO ที่มีการแก้ไขที่เกี่ยวข้อง:

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($2 in dict) ? dict[$2] : $2}1' file2.txt file1.txt 
item1 platA
item2 platB
item3 platC
item4 platD
item5 platE

แนวคิดคือการสร้างแฮชแผนที่พร้อมดัชนีและใช้เป็นพจนานุกรม

สำหรับคำถามที่ 2 ที่คุณถามในความคิดเห็นของคุณ ( สิ่งที่ควรเปลี่ยนหากคอลัมน์ที่สองของfile1.txtจะเป็นคอลัมน์ที่หก ):

หากไฟล์อินพุตจะเป็นfile1b.txtดังนี้:

item1 A5 B C D carA
item2 A4 1 2 3 carB
item3 A3 2 3 4 carC
item4 A2 4 5 6 platD
item5 A1 7 8 9 carE

คำสั่งต่อไปนี้จะทำ:

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($6 in dict) ? dict[$6] : $6;$3="";$4="";$5="";$6=""}1' file2.txt file1b.txt 
item1 platA    
item2 platB    
item3 platC    
item4 platD    
item5 platE    

1
@pawana - ฉันได้อัปเดตคำตอบเพื่อแก้ไขคำถามที่สองของคุณในความคิดเห็นแล้ว หากฉันตอบคำถามของคุณโปรดยอมรับมัน
Yaron

6

ฉันรู้ว่าคุณพูดawkแต่มีjoinคำสั่งสำหรับวัตถุประสงค์นี้ ...

{
  join -o 1.1,2.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt)     
  join -v 1 -o 1.1,1.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt) 
} | sort -k 1

มันจะเพียงพอกับjoinคำสั่งแรกถ้ามันไม่ได้สำหรับบรรทัดนี้:

item4   platD

คำสั่งโดยทั่วไปบอกว่า: เข้าร่วมตามคอลัมน์ที่สองของไฟล์แรก ( -1 2) และคอลัมน์แรกของไฟล์ที่สอง ( -2 1) และส่งออกคอลัมน์แรกของไฟล์แรกและคอลัมน์ที่สองของไฟล์ที่สอง ( -o 1.1,2.2) นั่นแสดงให้เห็นเพียงเส้นที่จับคู่ คำสั่ง join ที่สองบอกว่าเกือบเหมือนกัน แต่มันบอกให้แสดงบรรทัดจากไฟล์แรกที่ไม่สามารถจับคู่ ( -v 1) และส่งออกคอลัมน์แรกของไฟล์แรกและคอลัมน์ที่สองของไฟล์แรก ( -o 1.1,1.2) จากนั้นเราเรียงลำดับผลลัพธ์ของทั้งสองรวมกัน sort -k 1หมายถึงการเรียงลำดับตามคอลัมน์แรกและsort -k 2หมายถึงการเรียงลำดับตามคอลัมน์ที่สอง joinสิ่งสำคัญคือการจัดเรียงไฟล์ตามคอลัมน์เข้าร่วมก่อนที่จะผ่านพวกเขาไป

ตอนนี้ฉันเขียนการเรียงลำดับสองครั้งเพราะฉันไม่ชอบทิ้งไฟล์ไดเรกทอรีด้วยไฟล์ถ้าฉันสามารถช่วยได้ อย่างไรก็ตามเช่นเดียวกับ David Foerster กล่าวขึ้นอยู่กับขนาดของไฟล์คุณอาจต้องการเรียงลำดับไฟล์และบันทึกก่อนเพื่อไม่ต้องรอเรียงลำดับสองครั้ง เพื่อให้เข้าใจถึงขนาดนี่คือเวลาที่ใช้ในการเรียงลำดับ 1 ล้านและ 10 ล้านบรรทัดบนคอมพิวเตอร์ของฉัน:

$ ruby -e '(1..1000000).each {|i| puts "item#{i}   plat#{i}"}' | shuf > 1million.txt 
$ ruby -e '(1..10000000).each {|i| puts "item#{i}   plat#{i}"}' | shuf > 10million.txt 
$ head 10million.txt 
item530284   plat530284
item7946579   plat7946579
item1521735   plat1521735
item9762844   plat9762844
item2289811   plat2289811
item6878181   plat6878181
item7957075   plat7957075
item2527811   plat2527811
item5940907   plat5940907
item3289494   plat3289494
$ TIMEFORMAT=%E
$ time sort 1million.txt >/dev/null
1.547
$ time sort 10million.txt >/dev/null
19.187

นั่นคือ 1.5 วินาทีสำหรับ 1 ล้านบรรทัดและ 19 วินาทีสำหรับ 10 ล้านบรรทัด


ในกรณีนี้จะเป็นการดีกว่าถ้าคุณเก็บข้อมูลอินพุตที่เรียงลำดับในไฟล์ชั่วคราว (ชั่วคราว) เนื่องจากการเรียงลำดับใช้เวลาค่อนข้างนานสำหรับชุดข้อมูลที่ไม่ได้มีขนาดใหญ่ มิฉะนั้น +1
David Foerster

@ David เป็นจุดที่ดี โดยส่วนตัวแล้วฉันไม่ชอบที่จะสร้างไฟล์ระดับกลาง แต่ฉันก็ใจร้อนกับกระบวนการที่ใช้เวลานาน ฉันสงสัยว่า "ขนาดเล็ก" จะเป็นเช่นไรดังนั้นฉันจึงสร้างเกณฑ์มาตรฐานขนาดเล็กและเพิ่มคำตอบพร้อมกับคำแนะนำของคุณ
JoL

ในการจัดเรียงเร็กคอร์ด 1 mio นั้นเร็วพอสำหรับคอมพิวเตอร์เดสก์ท็อปที่ทันสมัยพอสมควร เมื่อขนาดของคำสั่งซื้อเพิ่มขึ้นอีก 2 ขนาดยิ่งเพิ่มสิ่งที่น่าสนใจมากขึ้น ในกรณีใด ๆ เวลาที่ผ่านไป (จริง) ( %Eในรูปแบบเวลา) มีความน่าสนใจน้อยกว่าในการวัดประสิทธิภาพการคำนวณ เวลา CPU ของโหมดผู้ใช้ ( %UหรือTIMEFORMATตัวแปรที่ไม่ได้ตั้งค่า) จะมีความหมายมากกว่านี้มาก
David Foerster

@ David ฉันไม่คุ้นเคยกับกรณีการใช้งานในเวลาที่ต่างกัน ทำไมมันน่าสนใจมากกว่านี้? เวลาที่ผ่านไปคือสิ่งที่เกิดขึ้นพร้อมกับเวลาที่ฉันรออยู่ สำหรับคำสั่งที่สอง 1.5, ฉันได้รับ 4.5 %Uวินาทีกับ
JoL

1
เวลาที่ผ่านไปจะได้รับผลกระทบจากเวลาที่ใช้ในการรองานอื่น ๆ ที่รันบนระบบเดียวกันและการบล็อกคำขอ I / O (ผู้ใช้) เวลา CPU ไม่ใช่ โดยทั่วไปเมื่อเปรียบเทียบความเร็วของอัลกอริธึมที่ผูกกับการคำนวณเราต้องการละเว้น I / O และหลีกเลี่ยงข้อผิดพลาดในการวัดเนื่องจากงานพื้นหลังอื่น ๆ คำถามที่สำคัญคือ "อัลกอริทึมนี้ต้องใช้การคำนวณจำนวนเท่าใดในชุดข้อมูลนั้น" แทนที่จะเป็น "คอมพิวเตอร์ของฉันใช้เวลากับภาระงานทั้งหมดเท่าไรในขณะที่รอให้การคำนวณเสร็จสมบูรณ์"
David Foerster
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.