เปรียบเทียบสองไฟล์กับคอลัมน์แรกและลบแถวที่ซ้ำกันออกจากไฟล์ที่ 2 ในเชลล์สคริปต์


9

ฉันจะถามคำถามของฉันพร้อมตัวอย่าง ฉันมี 2 ไฟล์:

ไฟล์ # 1:

118D FC300_R5_TP  FX.B      32775       2112   6       2038   6       2112   0
118E FC300_R5_TP  FX.B      32775       2136   7       2065   6       2136   0
118F FC300_R5_TP  FX.B      32775       2124   6       2064   6       2124   0
1190 FC300_R5_TP  FX.B     819210     814632  99     814609  99     814632   0
1191 FC300_R5_TP  FX.B     819210     104100  13     103714  13     104100   0
1192 FC300_R5_TP  FX.B    1638420    1609476  98    1609402  98    1609476   0
1196 FC300_R5_TP  FX.B    1638420    1638432 100    1638379 100    1638432   0
119A FC300_R5_TP  FX.B    3276840    3271776 100    3271698 100    3271776   0
119E FC300_R5_TP  FX.B    3276840    3264120 100    3264034 100    3264120   0
11A2 FC300_R5_TP  FX.B    3276840    2328648  71    2328546  71    2328648   0
11A6 FC300_R5_TP  FX.B    3276840    2328444  71    2328355  71    2328444   0
11AA FC300_R5_TP  FX.B    3276840    2328528  71    2328403  71    2328528   0
11AE FC300_R5_TP  FX.B    3276840    2328648  71    2328468  71    2328648   0
11B2 FC300_R5_TP  FX.B    3276840    2130000  65    2129766  65    2130000   0
173A FC300_R5_TP  FX.B    6553680    6478572  99    6477747  99    6478572   0

ไฟล์ # 2:

11AA FC300_R5_TP  FX.B    3276840    2328528  71    2328403  71    2328528   0
11AE FC300_R5_TP  FX.B    3276840    2328648  71    2328468  71    2328648   0
11B2 FC300_R5_TP  FX.B    3276840    2130000  65    2129766  65    2130000   0
173A FC300_R5_TP  FX.B    6553680    6478572  99    6477747  99    6478572   0
0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

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

ไฟล์ # 3:

0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

ฉันต้องการเปรียบเทียบไฟล์ 1 และไฟล์ 2 โดยใช้คอลัมน์แรกและลบทั้งบรรทัดหรือแถวออกจากไฟล์ 2 ที่ตรงกับในไฟล์ 1 ฉันต้องการบันทึกผลลัพธ์เป็นไฟล์ที่ 3 ไฟล์ # 3

คำตอบ:


10

คุณสามารถใช้awkสิ่งนี้:

awk 'FNR==NR{a[$1];next};!($1 in a)' file1 file2 > file3

คำอธิบาย:

  • FNR == NR: การทดสอบนี้เป็นจริงเมื่อจำนวนของระเบียนเท่ากับจำนวนของระเบียนในไฟล์ นี่คือความจริงเพียง แต่สำหรับไฟล์แรกสำหรับไฟล์ที่สองNRจะเท่ากับจำนวนของเส้นของ file1 เครื่องหมาย FNR+

  • a[$1]: สร้างดัชนีองค์ประกอบอาร์เรย์ของฟิลด์แรกของ file1

  • next: ข้ามไปยังระเบียนถัดไปเพื่อไม่ให้มีการประมวลผลเพิ่มเติมใน file1

  • !($1 in a): ดูว่ามีฟิลด์แรก ($ 1) อยู่ในอาร์เรย์หรือไม่เช่นใน file1 และพิมพ์ทั้งบรรทัด (ไปยัง file3)

ขึ้นอยู่กับหนึ่งในตัวอย่างจากวิกิพีเดีย #awk


คำตอบที่สมบูรณ์แบบ !!!
mtk

8
export LC_ALL=C
comm -13 <(sort f1) <(sort  f2)

f2จะรายงานเส้นที่มีเฉพาะใน

export LC_ALL=C
join -v2 <(sort f1) <(sort f2)

จะรายงานสายของมีฟิลด์แรกไม่พบเป็นสนามแรกในสายใดf2f1

(คุณต้องเปลือกด้วยการสนับสนุนกระบวนการทดแทนเช่นksh93, zshหรือbash)


2

เพียงเพื่อความสนุกนี่คือทางออกใน Perl:

#!/usr/bin/perl

# create names lookup table from first file
my %names;
while (<>) {
    (my $col1)= split / /, $_;
    $names{$col1} = 1;
    last if eof;
}

# scan second file
while (<>) {
    print if /^(\S+).*/ && not $names{$1};
}

ตัวอย่าง

$ ./showdiffs.pl file1  file2
0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

รายละเอียด

โซลูชัน Perl ด้านบนประกอบด้วย 2 ลูป การวนซ้ำครั้งแรกจะอ่านบรรทัดทั้งหมดจากfile1และสร้างแฮชโดย%namesที่แต่ละคอลัมน์ที่เราระบุจะถูกเพิ่มเข้าไป

$names{11AA} = 1;

whileจากนั้นลูปที่2 จะรันบนไฟล์ที่ 2 file2และคอลัมน์ 1 ของแต่ละบรรทัดจะถูกระบุโดยใช้นิพจน์ทั่วไป:

^(\S+).*

$1ดังกล่าวข้างต้นกล่าวว่าจากจุดเริ่มต้นของสายการแข่งขันทุกอย่างที่ไม่พื้นที่และบันทึกไว้ในตัวแปรชั่วคราว มันถูกบันทึกไว้โดยห่อล้อมรอบมัน .*กล่าวว่าเพื่อให้ตรงกับทุกสิ่งทุกอย่างในบรรทัด

บิตถัดไปของเส้นที่บอกว่าจะมองขึ้นบิต 1 คอลัมน์ที่เราเพิ่งบันทึกไว้ใน$1ใน%namesกัญชา:

$names{$1}

หากมีอยู่ที่นั่นเราไม่ต้องการพิมพ์ หากไม่มีให้พิมพ์ออกมา


2

วิธีที่ 1 # Bash

#!/usr/bin/env bash
file1=$1
file2=$2

[[ $# -ne 2 ]]  && { echo -e "\n\tUsage: \t$0 file1 file2\n"; exit 1; }

while read line
do

        if ! grep -q "${line%% .*}" $file1; then
                echo "${line}"
        fi

done < $file2

วิธีที่ 2 # Grep เท่านั้น

grep -v "$(< file1)" file2

grep กำลังทำงาน แต่ไม่รับประกัน


1

ให้ได้มันเป็น

ไฟล์ # 1: file1.txt

ไฟล์ # 2: file2.txt

จากนั้นเรียกใช้งานบนเทอร์มินัล

fgrep -vf test1.txt test2.txt > output.txt

output.txt จะมีผลลัพธ์ที่ต้องการ

คำอธิบาย:

fgrep : print lines matching a pattern (from manual page)
-v  : get only non-matching rows
-f : obtain PATTERN from FILE (from manual page)

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