簡體   English   中英

條件Awk hashmap匹配查找

[英]Conditional Awk hashmap match lookup

我有2個表格文件。 一個文件包含50個鍵值的映射,僅稱為lookup_file.txt。 另一個文件具有30列和數百萬行的實際表格數據。 data.txt我想用lookup_file.txt中的值替換第二個文件的id列

我怎樣才能做到這一點? 我更喜歡在bash腳本中使用awk ..此外,是否有一個hashmap數據結構我可以在bash中用於存儲50個鍵/值而不是另一個文件?

假設您的文件有逗號分隔的字段,“id列”是字段3:

awk '
BEGIN{ FS=OFS="," }
NR==FNR { map[$1] = $2; next }
{ $3 = map[$3]; print }
' lookup_file.txt data.txt

如果這些假設中的任何一個是錯誤的,請告訴我們如果修復不明顯......

編輯:如果你想避免(恕我直言可以忽略不計)NR == FNR測試性能影響,這將是使用getline時適用的每種罕見情況之一:

awk '
BEGIN{
   FS=OFS=","
   while ( (getline line < "lookup_file.txt") > 0 ) {
      split(line,f)
      map[f[1]] = f[2]
   }
}
{ $3 = map[$3]; print }
' data.txt

您可以通過bash混合使用“sort”和“join”,而不必將其寫入awk / sed,它可能更快:

key.cvs(id,name)

1,homer
2,marge
3,bart
4,lisa
5,maggie

data.cvs(姓名,動物,所有者,年齡)

snowball,dog,3,1
frosty,yeti,1,245
cujo,dog,5,4

現在,您需要首先在用戶ID列上對這兩個文件進行排序:

cat key.cvs | sort -t, -k1,1 > sorted_keys.cvs
cat data.cvs | sort -t, -k3,3 > sorted_data.cvs

現在加入2個文件:

join -1 1 -2 3 -o "2.1 2.2 1.2 2.4" -t , sorted_keys.cvs sorted_data.cvs > replaced_data.cvs

這應該產生:

snowball,dog,bart,1
frosty,yeti,homer,245
cujo,dog,maggie,4

這個:

-o "2.1 2.2 1.2 2.4"

在最終輸出中說出你想要的2個文件中的哪些列。

與其他腳本語言相比,查找和替換多個數據的速度非常快。 我還沒有直接與SED / AWK進行比較,但編寫一個包裝它的bash腳本比寫入SED / AWK(至少對我來說)要容易得多。

此外,您可以使用gnu coreutils的升級版本加快排序速度,以便您可以並行執行排序

cat data.cvs | sort --parallel=4 -t, -k3,3 > sorted_data.cvs

4是你要運行它的線程數。我建議每個機器核心2個線程通常會最大化機器,但如果它專用於此,那很好。

有幾種方法可以做到這一點。 但是如果你想要一個簡單的一個襯墊,沒有太多的驗證方式,我會選擇awk / sed解決方案。

假設如下:

  1. 文件是制表符分隔的

  2. 你正在使用bash shell

  3. 數據文件中的id位於第一列

  4. 你的文件看起來像這樣:

抬頭

1   one
2   two
3   three
4   four
5   five

數據

1   col2    col3    col4    col5
2   col2    col3    col4    col5
3   col2    col3    col4    col5
4   col2    col3    col4    col5
5   col2    col3    col4    col5

我會使用awksed來完成這個任務,如下所示:

awk '{print "sed -i s/^"$1"/"$2"/ data"}' lookup | bash

這樣做是通過每行查找並將以下內容寫入stdout

sed -is/^1/one/ data

sed -is/^2/two/ data

等等。

它接下來將每一行傳遞給shell( | bash ),它將執行sed表達式。 -i for -i.bak ,您可能需要-i.bak來創建備份文件。 請注意,您可以將擴展名更改為您想要的任何內容。 sed正在查找行開頭的id,如^ 您不希望替換可能不包含id的列中的“id”。

您的輸出將如下所示:

one     col2    col3    col4    col5
two     col2    col3    col4    col5
three   col2    col3    col4    col5
four    col2    col3    col4    col5
five    col2    col3    col4    col5

當然,你的id可能不是簡單的1比1,2比2等,但這可能會讓你開始朝着正確的方向前進。 我非常寬松地使用右邊的術語。

我這樣做的方法是使用awk編寫一個awk程序來處理更大的文件:

awk -f <(awk '
   BEGIN{print " BEGIN{"}
        {printf "      a[\"%s\"]=\"%s\";",$1,$2}
   END  {print "      }";
         print "      {$1=a[$1];print $0}"}
   ' lookup_file.txt
) data.txt

這假設id列是第1列; 如果沒有,你需要改變$1 $1=a[$1]兩個實例$1=a[$1]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM