Bash

刪除重複列表,但對其中的部分進行分組

  • May 2, 2022

我正在從失敗的登錄中編譯一些訪問規則,經過一些管道我到達了這個:

cat <<INPUT | sort -k 3,3 --unique
Deny from 13.42.98.142 # demo
Deny from 13.42.98.142 # test
Deny from 13.42.98.142 # user
Deny from 133.142.200.152 # admin
INPUT

只是出於興趣,我想保留嘗試過的登錄名(最後一個欄位)。我的測試程式碼將輸出:

Deny from 13.42.98.142 # demo
Deny from 133.142.200.152 # admin

我正在尋找類似的輸出:

Deny from 13.42.98.142 # demo, test, user
Deny from 133.142.200.152 # admin

甚至更好(因為它是有效的.htaccess語法):

# demo, test, user
Deny from 13.42.98.142
# admin
Deny from 133.142.200.152

注意:輸入就是我現在所做的——我並不固執,如果它更適合優雅的解決方案,我可以改變它。我也會接受一般性的答案,如何在 shell 中實現列表中的分組。

這是一個任務awk

awk -F'#' '
   { a[$1] = (a[$1] ? a[$1] "," $2 : $2) }
   END { for(x in a) print "#" a[x] ORS x }
' file

# admin
Deny from 133.142.200.152 
# demo, test, user
Deny from 13.42.98.142 

修改最後一條print語句,可以實現各種輸出格式。記錄的順序不是按任何鍵排序的,我假設您不需要它來達到您的目的。

如果我們需要按鍵排序(作為字元串,升序),使用 GNU awk,我們可以添加

PROCINFO["sorted_in"] = "@ind_str_asc"

for循環之前。參考:GNU awk 數組排序

使用 GNUdatamash按第一個#-delimited 欄位分組並折疊第二個欄位:

datamash -s -t '#' groupby 1 collapse 2 <<'END_RULES'
Deny from 13.42.98.142 # demo
Deny from 13.42.98.142 # test
Deny from 13.42.98.142 # user
Deny from 133.142.200.152 # admin
END_RULES

-s選項對輸入數據進行排序,在這種情況下這不是絕對必要的,因為它似乎已經排序。

輸出:

Deny from 13.42.98.142 # demo, test, user
Deny from 133.142.200.152 # admin

引用自:https://unix.stackexchange.com/questions/701029