เชื่อมต่อบรรทัดตามคอลัมน์แรกโดย awk หรือ sed


12

ฉันจะใช้awkในสถานการณ์ต่อไปนี้ได้อย่างไร?

ฉันต้องการเชื่อมโยงบรรทัดที่ขึ้นต้นด้วยคอลัมน์เดียวกัน เฉพาะคอลัมน์แรกจะถูกเก็บไว้หลังจากที่เข้าร่วม (ในกรณีนี้aaa, www, hhh)

ไฟล์อาจคั่นด้วยช่องว่างหรือแท็บ

อินพุตตัวอย่าง:

aaa bbb ccc ddd NULL NULL NULL
aaa NULL NULL NULL NULL NULL NULL
aaa bbb ccc NULL NULL NULL NULL
www yyy hhh NULL NULL NULL NULL
hhh 111 333 yyy ooo hyy uuuioooy
hhh 111 333 yyy ooo hyy NULL

ผลลัพธ์ที่ต้องการ:

aaa bbb ccc ddd NULL NULL NULL NULL NULL NULL NULL NULL NULL bbb ccc NULL NULL NULL NULL
www yyy hhh NULL NULL NULL NULL
hhh 111 333 yyy ooo hyy uuuioooy 111 333 yyy ooo hyy NULL

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


1
ไม่ที่uuuสายมาจาก (ในการส่งออก)?
saeedn

ขอโทษฉันไม่ดี ฉันจะแก้ไข
เล็ก ๆ

คำตอบ:


8

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

< testfile awk '{print $1}'
aaa
aaa
aaa
www
hhh
hhh

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

< testfile awk '{table[$1]=table[$1] $2;} END {for (key in table) print key " => " table[key];}'
www => yyy
aaa => bbbNULLbbb
hhh => 111111

ในการรับส่วนที่เหลือทั้งหมดของบรรทัดเริ่มต้นด้วยคอลัมน์ 2 คุณต้องรวบรวมคอลัมน์ทั้งหมด:

< testfile awk '{line="";for (i = 2; i <= NF; i++) line = line $i " "; table[$1]=table[$1] line;} END {for (key in table) print key " => " table[key];}'
www => yyy hhh NULL NULL NULL NULL 
aaa => bbb ccc ddd NULL NULL NULL NULL NULL NULL NULL NULL NULL bbb ccc    NULL NULL NULL NULL 
hhh => 111 333 yyy ooo hyy uuuioooy 111 333 yyy ooo hyy NULL 

สวัสดีใช่จำเป็นต้องมีการแบ่งตารางแฮช ขอบคุณ!
เล็ก ๆ

2
@tiny - ฉันกำลังสมมติว่าจำเป็นต้องรักษาลำดับ นี่ไม่ใช่กรณี (คำตอบนี้สร้างคำสั่งซื้อที่สอดคล้องกับกลไกการแปลงข้อมูลไม่ใช่คำสั่งดั้งเดิมของคุณ) หรือไม่
ire_and_curses

3

บุคคลอื่นสามารถตอบคำถามใน awk หรือ sed แต่เวอร์ชัน Python นั้นตรงไปตรงมาและอาจเป็นประโยชน์กับคุณ

#!/usr/bin/env python

input_file = 'input.dat'
in_fh      = open(input_file, 'r')

input_order = []
seen        = {}
for line in in_fh:    
    # Remove the newline character...
    line = line[:-1]

    # Separate the first column from the rest of the line...
    key_col, sep, rest_of_line = line.partition(" ")
    rest_of_line = sep + rest_of_line  

    # If we've seen this key already, concatenate the line...
    if key_col in seen:
        seen[key_col] += rest_of_line
    # ...otherwise, record the ordering, and store the new info
    else:
        input_order.append(key_col)
        seen[key_col] = rest_of_line

in_fh.close()

# Dump the ordered output to stdout
for unique_col in input_order:
    print unique_col + seen[unique_col]

เด็ดมาก กับงูหลามศูนย์ประสบการณ์ของฉันฉันยังมีการจัดการเพื่อแก้ไขสคริปต์ว่าจะใช้เวลาอาร์กิวเมนต์แรกเป็นชื่อแฟ้มใส่ :)
เล็ก

2

นี่เป็นแอปพลิเคชั่นที่น่าสนใจของ coreutils ฉันสงสัยว่ามันไม่ได้มีประสิทธิภาพมากกับอินพุตขนาดใหญ่เนื่องจากจะเรียกเข้าร่วมสำหรับแต่ละบรรทัดในอินพุต

touch outfile
while read; do
  join -a1 -a2 outfile <(echo $REPLY) > tmp
  mv tmp outfile
done < infile

เพื่อปรับปรุงประสิทธิภาพของมันการประหยัดoutfileและtmpramdisk อาจช่วยได้

แก้ไข

หรือไม่มีไฟล์ชั่วคราว:

out=""
while read; do
  out=$(join -a1 -a2 <(echo -n "$out") <(echo -n "$REPLY"))
done < infile

echo "$out"

2

และนี่คือ PERL หนึ่งซับ:

$ perl -e 'my %h; while(<>){chomp; @a=split(/\s+/); $k=shift(@a); $h{$k}.=join(" ", @a) . " "; } map{$h{$_}=~s/\s*$//; print "$_ $h{$_}\n}keys(%hash);' infile
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.