2016-01-06 973 views
6

我有一個file1,有幾行(幾十),和一個更長的file2(〜500,000行)。每個文件中的行不相同,儘管有一些相同的字段的子集。我想從file1中的每一行獲取字段3-5,並搜索file2以獲得相同的模式(只是這三個字段按相同的順序排列 - 在file2中,它們落在字段2-4中)。如果發現任何匹配,那麼我想從file1中刪除相應的行。awk/sed/grep刪除與其他文件中的字段匹配的行

例如,文件1:

2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T07:53:50 2016-01-06T07:52:14 2016006 090E A TM Current 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

文件2:

2016-01-06T07:35:06.87 2016003 100E C NN Current 0 
2016-01-06T07:35:09.97 2016003 100E B TM Current 6303 
2016-01-06T07:36:23.12 2016004 030N C TM Current 0 
2016-01-06T07:37:57.36 2016006 090E A TM Current 399 
2016-01-06T07:40:29.61 2016006 010N C TM Current 0 

...(以及50萬線)

因此,在這種情況下,我想刪除第四行文件1(到位)。

下找到行我想刪除:

grep "$(awk '{print $3,$4,$5}' file1)" file2 

所以,一個解決辦法可能是管這sed的,但我不清楚如何從管道輸入sed的設置匹配模式。在線搜索表明awk可能會做所有這些(或者可能是sed或其他),所以想知道乾淨的解決方案是什麼樣的。

另外,速度有點重要,因爲其他進程可能會嘗試修改這些文件(我知道這可能會帶來更多複雜性......)。匹配通常會在file2的末尾找到,而不是開頭(如果有某種方法從下往上搜索file2)。

+0

時脈聯合國辦事處的出色那樣的問題。繼續發帖並祝你好運。 – shellter

回答

4
$ awk 'NR==FNR{file2[$2,$3,$4]; next} !(($3,$4,$5) in file2)' file2 file1 
2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

該文件2包含50萬行應該是AWK WRT內存或執行速度沒有問題的事實 - 它應該完成約1秒或更少,即使在最壞的情況下。

對於任何UNIX命令,覆蓋你只是做原始文件:

cmd file > tmp && mv tmp file 

所以在這種情況下:

awk '...' file2 file1 > tmp && mv tmp file1 
+0

謝謝。我看到這是如何工作的,而且非常快。我試圖以相反的方式做到這一點,將file1讀入一個數組(因爲它非常小),但我不清楚如何從file1打印出不匹配的行。 – trid3

+0

所以現在你知道將file1讀入數組是錯誤的方法,對吧?這樣做會節省你的內存,但是你需要爲文件2的每一行循環遍歷整個file1數組,這樣會增加腳本運行的時間量,文件1。 –

+0

例如,像這樣:awk'NR == FNR {file1 [$ 3,$ 4,$ 5];下一步}!(($ 2,$ 3,$ 4)in file1){print XX}'file1 file2。 XX會是什麼?如果我們可以簡單地grep file1($ 2,$ 3,$ 4)(現在我們知道它不存在於file2中)並打印出來,那就可以做到這一點。 – trid3

1

可以在file1找到不匹配的行:

$ grep -v -F -f <(awk '{ print $3,$4,$5 }' file2) file1 
2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

只是重定向這個地方,並覆蓋file1之後。

+0

絕對不要這樣做,即使它可能會產生預期的輸出給定此示例輸入,一般情況下,你會得到錯誤的匹配,這取決於兩個文件的內容,因爲它在整個每一行中grep for file2內容而不是隻在file1的目標字段中。 –

相關問題