![Uniq 由兩個條件的兩個欄位組成](https://rvso.com/image/697372/Uniq%20%E7%94%B1%E5%85%A9%E5%80%8B%E6%A2%9D%E4%BB%B6%E7%9A%84%E5%85%A9%E5%80%8B%E6%AC%84%E4%BD%8D%E7%B5%84%E6%88%90.png)
我有帶列的表格。在第一列中,我有時間,當使用者登入時,在第二列中,我有使用者名稱。
13:15:39 fxs1cia1qulm1lk
13:15:39 fxs1cia1qulm1lk
13:15:39 fxs1cia1qulm1lk
13:15:42 faaaa2aa11111
13:15:49 terd1sfsd11fsdf
13:15:49 terd1sfsd11fsdf
13:15:49 terd1sfsd11fsdf
13:15:59 21erdsf123sdfsdf
13:15:59 21erdsf123sdfsdf
13:15:59 21erdsf123sdfsdf
13:15:59 21erdsf123sdfsdf
13:17:50 abcasbbabadab
13:17:50 abcasbbabadab
13:17:50 abcasbbabadab
13:17:50 abcasbbabadab
13:19:19 fxs1ce1iulmla
13:19:19 fxs1ce1iulmla
13:19:19 fxs1ce1iulmla
13:20:42 faaa2a0a1111
那麼,我該做什麼。我應該對這兩個欄位進行 uniq 操作,並且如果使用者登入時間和使用者名稱相同,我應該說該使用者已登入超過 3 次。我寫了一個簡短的腳本:
log_file=/root/log
temp_file=/root/temp
temp_file2=/root/temp2
cat /dev/null > $temp_file
cat /dev/null > $temp_file2
cat /dev/null > $result_file
cat $log_file | awk '{print $1}' | tail -n 20 > $temp_file
cat $log_file | awk '{print $5}' | tail -n 20 > $temp_file2
for i in `uniq -c $temp_file | awk '{print $1}'`; do
for y in `uniq -c $temp_file2 | awk '{print $2}'`; do
if [ $i -gt 3 ] && [ $y -gt 3 ]; then
s=`uniq -c $temp_file2 | awk '$1 == '$i`
echo "The user $s has logged more than 3 times"
fi
done
done
請檢查一下,這個腳本是否正確?因為,在 echo 中輸出我的腳本後,我有:
The user 4 21erdsf123sdfsdf
4 abcasbbabadab has logged more than 3 times
The user 4 21erdsf123sdfsdf
4 abcasbbabadab has logged more than 3 times
The user 4 21erdsf123sdfsdf
4 abcasbbabadab has logged more than 3 times
The user 4 21erdsf123sdfsdf
4 abcasbbabadab has logged more than 3 times
但我想要這樣的輸出:
The user 4 21erdsf123sdfsdf has logged more than 3 times
The user 4 abcasbbabadab has logged more than 3 times
就這樣。我哪裡有錯誤?請幫忙。
答案1
您可以透過非常簡單的方式執行此操作awk
awk '{ users[$2]++ }
END {
for (user in users)
if (users[user] > 1)
printf "%s logged in %d times\n", user, users[user]
}' < /root.log
程式掃描 root.log,建立一個包含每個使用者計數的關聯數組(也稱為雜湊),然後列印大於 1 的陣列。
答案2
那麼,唯一的問題是它多次列印相同的輸出?為什麼不直接透過 uniq 進行管道傳輸呢?轉儲到另一個臨時文件,然後在其上執行 uniq?
如果這不是你要問的,我有一些觀察:
- 在 bash/sh 中處理行分隔的資料通常比它的價值更麻煩。除非解決方案很明顯,否則請使用腳本語言,這樣您就不必一直擺弄 IFS。 (如果您不知道 IFS var 是什麼,那麼我真的建議遠離 bash/sh 來獲取行分隔資料。)
- 既然您已經在使用 awk,我打賭您可以將整個事情作為 awk 腳本來完成。
- 由於您關心的行是相同的,因此您可以這樣做
sort logfile | uniq -c
。 - 您不會在 uniq 之前對文件進行排序,因此如果相同的行不相鄰,uniq 將無法運作。例如,如果 bob 和 joe 同時登入並且他們的日誌條目交替。
- 總是有 grep -c
- 閱讀排序指令,特別是 -d、-n、-k 和 -t
更新
您是在尋求有關 shell 腳本編寫的建議,還是在尋找「如何找出誰目前登入了 3 個或更多會話」這一問題的實際答案?
腳本建議:
- 我很確定
$s
包含整個字串,4 21erdsf123sdfsdf <newline> 4 abcasbbabadab
包括換行符。我不太明白為什麼。 - 為什麼這麼做
awk '{print $5}'
?我嘗試複製您的範例資料並運行它awk '{print $5}'
,但我得到了一堆換行符,沒有其他任何內容。 - 您是否已查看
$temp_file
並$temp_file2
確保它們符合您的預期? - 告訴
tail -n 20
我你只想要「最近」的條目,而不在乎有多新。這是真的? - 這些
cat /dev/null > $file
線是多餘的,把它們去掉就好了。 - 替換
cat $logfile
為sort $logfile
- 縮進你的循環
基本上這個腳本不會做你想要的事情,而且我無法告訴你它是如何運作的,所以我不能給出更具體的建議。對不起。
實際的
- 使用 @greg-tarsa 的 awk 腳本('向'e道歉,Greg me heartie,我不知道'o'鏈接't'用戶,我們'是名字中的空格)
- 你是在談論目前登入unix 盒子的情況嗎?你嘗試過
who
命令嗎? EGwho | awk '{ print $1}' | sort | uniq -c | sort -d -r
還是last
指令? - 搜尋您的整體問題的答案(我如何找出誰登入/登入次數過多),而不是阻止您已經嘗試實現的解決方案的更具體的問題(Uniq 由兩列和兩個條件) 。如果您對練習 shell 腳本更感興趣,請以這樣的方式提出您的問題。