靈活的模式匹配
我有一個看起來像這樣的文件:
文件1:
0/28 7200/11 14400/11 21584/28 21600/11 28800/28 36000/11 36000/28 43200/11 43200/28 50400/11 57600/11 79200/28
在左側(在 / 之前)我有以秒為單位的時間,而在右側我有一個相應秒的參數值。
現在我有另一個看起來像這樣的文件:
文件2:
0 14 0 15 0 20 0 28 7200 11 7200 14 7200 15
現在,我想從第二個文件中刪除 FILE1 中的公共值。例如,我應該從 FILE2 中刪除:
0 28 7200 11
並保持其餘行不變。
我正在考慮在 bash 腳本中為 FILE1 中的每一行使用 for 循環,然後在 FILE2 中搜尋它,但我無法辨識該模式。如果我嘗試從 awk 使用 substr 它將不起作用,因為時間沒有相同的數字(0 有 1 個數字,7200 有 4 個數字)。
要閱讀 FILE1 我正在做這樣的事情:
IFS=$'\n' read -d '' -r -a X < ./FILE1.csv
為了編寫 for 循環,我正在做這樣的事情:
for x in "${X[@]}" do gawk -i inplace -v var=${x} '{...}' FILE2.csv done
我也在考慮將 FILE1 轉換為這樣的東西:
0 28 7200 11 14400 11 21584 28 21600 11 28800 28 36000 11 36000 28 43200 11 43200 28 50400 11 57600 11 79200 28
基本上有 2 列,但使用我上面使用的 for 和 var,如果我有超過 1 列,則將不起作用。我認為第二種方法更好,但我不知道如何讓它單獨處理每一列。
編輯:
如果 FILE1 是,我將如何做到這一點:
0 28 7200 11 14400 11 21584 28 21600 11 28800 28 36000 11 36000 28 43200 11 43200 28 50400 11 57600 11 79200 28
文件 2 是:
0 14 2 19 0 15 157 67 0 20 28 57 0 28 25 67 7200 11 88 14 7200 14 34 247 7200 15 364 14
使用
awk
:awk 'NR==FNR { sec[$1, $2]; next } !($1, $2) in sec' FS='/' file1 FS=' ' file2 0 14 0 15 0 20 7200 14 7200 15
每個輸入文件之前的
FS
(欄位分隔符)定義該文件的欄位分隔符。
最後回答添加的問題:
$ join -v 2 <(sed 's/ /:/' file1) <(sed 's/ /:/' file2) | sed 's/:/ /' 0 14 2 19 0 15 157 67 0 20 28 57 7200 14 34 247 7200 15 364 14
與
join
此答案中的其他變體(提供原始問題的答案)一樣,這確保連接鍵是沒有空格的單個字元串,然後從第二個文件中選擇要連接的行key 與第一個文件中的任何條目都不匹配。這對必須以相同方式排序的文件做出了相同的假設。就像
join
一次只在記憶體中保留兩行一樣,我們仍然有相同的好處,grep
以及需要將一個文件中的所有條目保留在記憶體中的任何其他解決方案。使用原始文件
file1
和file2
您的問題,將第一個文件tr
即時轉換為與第二個文件相同的格式,並使用重新格式化的數據作為一組行從第二個文件中刪除。$ grep -v -x -F -f <(tr '/' ' ' <file1) file2 0 14 0 15 0 20 7200 14 7200 15
該
grep
實用程序在這裡用於過濾掉(刪除、排除)file2
與來自file1
.該
-x
選項強制進行全行匹配(不是通常的子字元串匹配),並將模式用作固定字元串而不是正則表達式-F
。grep
該-f
選項告訴實用程序從命名文件中讀取模式(程序替換),並-v
反轉匹配的通常含義,以便輸出不匹配的行。也與您問題中的一些文字相關:
一種更有效的方法是使用
join
.file1
如果你很大,這可能是個好主意。在大量輸入上,這預計會比使用grep
.下面假設您的兩個文件都以相同的方式排序,並將第二個文件轉換為與第一個文件相同的格式(用斜杠替換空格)以生成沒有空格的行。我們以這種方式進行轉換,
join
預設情況下使用空格作為分隔符,我們需要考慮整行,而不僅僅是第一個空格分隔的欄位。$ join -v 2 file1 <(tr ' ' '/' <file2) | tr '/' ' ' 0 14 0 15 0 20 7200 14 7200 15
這將在兩個數據集之間執行關係 JOIN 操作,並將第二個輸入中不匹配的行返回到
join
(轉換後的第二個文件)。由於我們希望將空格分隔的數據作為最終結果,因此我們將最後的斜杠替換為空格。這在任何時候都不會在記憶體中保存超過兩行的數據,而
grep
變體需要將第一個文件的全部內容保留在記憶體中,並且還需要針對第二個文件的每一行測試該文件的每一行文件。