通过两个条件的两列进行 Uniq

通过两个条件的两列进行 Uniq

我有一张包含多个列的表格。第一列是时间,即用户登录的时间;第二列是用户名。

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

那么,我应该怎么做呢?我应该对这两列进行唯一性迭代,如果用户登录的时间和用户名相同,我应该说该用户登录了 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 创建一个包含每个用户计数的关联数组(又名哈希),然后打印大于一的数组。

答案2

那么,唯一的问题是它多次打印相同的输出?为什么不直接通过 uniq 管道?转储到另一个临时文件,然后在其上运行 uniq?

如果这不是你想问的,我有一些观察:

  • 在 bash/sh 中处理行分隔数据通常麻烦多多。除非解决方案显而易见,否则请使用一种您不必一直摆弄 IFS 的脚本语言。(如果您不知道 IFS 变量是什么,那么我真的建议不要使用 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 $logfilesort $logfile
  • 缩进循环

基本上,这个脚本不会按照你的要求运行,我也不知道你希望它如何工作,所以我无法提供更具体的建议。抱歉。

实际的

  • 使用@greg-tarsa 的 awk 脚本(对不起,Greg,我不知道链接中的用户是否在名字中有一个空格)
  • 您是在谈论当前登录到 unix 框的情况吗?您尝试过该who命令吗?例如,who | awk '{ print $1}' | sort | uniq -c | sort -d -r还是该last命令?
  • 搜索您总体问题的答案(如何找出谁登录了/登录了太多次),而不是阻碍您已尝试实施的解决方案的更具体的问题(使用两个条件通过两列进行 Uniq)。如果您对练习 shell 脚本更感兴趣,请以这样的方式提问。

相关内容