使用awk對某列去重並且可保留其他列
阿新 • • 發佈:2019-02-03
同事說需要統計日誌中按url的path去重之後的結果,結果中要保留引數。相同url不同引數的,只保留第一行。
理論上各種命令都是流式處理,一行一行的處理。每道命令都相當於一個過濾器。比如你要按某列去重,則事先把資料cut到只剩你需要去重的這一列。對url中的path做sort+uniq。
但是這樣會導致引數都沒了。所以不能用這個。
最後成功的命令如下:
cut
-f 7 -d "
" access. 2018 - 01 - 11 .log
| sed 's/?/
/' |
awk '!a[$1]++{print}'
|
解釋一下
a[$1]是$1的hash值,在這裡是被作為變數名了,初始值為0,++表示在本行執行完畢之後+1
那麼awk走到第一行時,該變數剛剛初始化則是0,取反後為1,即為true,所以第一行會被print
第二行如果跟第一行的a[$1]一樣,則該變數的值已經在上一行被+1了,所以值不是0了,而是1。則取反之後值為0,即為false,則本行不print
第三行如果還一樣,則變數值為2,由於在C中,只要不是0就是真,所以第三行變數值取反為false,不print
---------------------------------------------------
後來同事又提了更過分的要求,想要把以上命令再結合ssh,從跳板機就直接遠端獲取到處理好的資料並寫入檔案,這樣不用一個個機器去登。
一開始是這樣寫的,會報錯。
ssh
xxxxx.beta.cn0 "zgrep
-e 'HTTP/1.0\" \(2\|3\)0' /xxxxxx/logs/access.2018-01-08.log | cut -f 7 -d ' '| sed 's/?/ /' | awk '!a[$1]++{print}' " >>
valid_access.log
報錯如下:
-bash:
!a[$ 1 ]++:
event not found
|
最後換了個思路,把awk放到本地執行,就解決了:
ssh
xxxxx.beta.cn0 "zgrep
-e 'HTTP/1.0\" \(2\|3\)0' /xxxxxx/logs/access.2018-01-08.log | cut -f 7 -d ' '| sed 's/?/ /' " |
awk '!a[$1]++{print}' >>
valid_access.log
|