使用 bash 和 awk 将日志文件分组
Sorting log file into groups with bash and awk
我正在尝试以特定方式对日志文件进行排序,但我不确定如何执行最后一步。
我的日志文件有这样的条目:
Feb 15 17:00:34 server sshd[13879]: Invalid user test from 200.242.94.133
Feb 15 17:00:35 server sshd[13780]: Invalid user ftpuser from 200.242.94.133
Feb 15 17:01:34 server sshd[13890]: Invalid user test from 200.242.94.133
Feb 15 17:01:35 server sshd[13791]: Invalid user vnc from 200.242.94.133
Feb 15 17:01:35 server sshd[13794]: Invalid user test from 50.63.172.108
Feb 15 17:01:36 server sshd[13798]: Invalid user vnc from 50.63.172.108
我使用命令:
cat logfile | grep "Invalid user" | awk '{print ", " }' | sort -t":" -k2,2 | uniq -c
输出:
1 ftpuser, 200.242.94.133
2 test, 200.242.94.133
1 test, 50.63.172.108
1 vnc, 200.242.94.133
1 vnc, 50.63.172.108
我想得到:
1 ftpuser, (1) 200.242.94.133
3 test, (2) 200.242.94.133, (1) 50.63.172.108
2 vnc, (1) 200.242.94.133, (1) 50.63.172.108
我不确定如何对单词列求和,同时保持 ip 地址单独计数,然后将其与其他结果一起包含。
尝试回答:
# awk '/Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}' logfile | sort -k2
awk: /Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}
awk: ^ syntax error
awk: /Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}
awk: ^ syntax error
awk: /Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}
awk: ^ syntax error
$ awk '/Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}' logfile
2 vnc, (1) 50.63.172.108, (1) 200.242.94.133
1 ftpuser, (1) 200.242.94.133
3 test, (1) 50.63.172.108, (2) 200.242.94.133
如果您希望它按用户字母顺序排序:
$ awk '/Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}' logfile | sort -k2
1 ftpuser, (1) 200.242.94.133
3 test, (1) 50.63.172.108, (2) 200.242.94.133
2 vnc, (1) 50.63.172.108, (1) 200.242.94.133
以上适用于 GNU awk
。我还没有用 BSD 测试过。
工作原理
/Invalid user/{user[]++;ip[][]++}
对于 logfile
中包含无效用户的任何行,这将计算用户名、字段 8 和 IP 地址、字段 10。
END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}
当我们读完 logfile
后,循环遍历我们看到的每个用户并打印我们看到该用户的次数,然后是该用户的名字,然后是每个 ip地址,该 ip 的计数,后跟该 ip。
是一个非常简洁且大概是快速的解决方案,是一个选项,IF:
- 您正在使用 GNU awk(该解决方案使用非 POSIX 功能,不能与 BSD awk 一起使用(也用于 OS X) 或 mawk,例如)。
- 您不介意看似随机的 IP 地址顺序(由于关联数组的未排序键枚举;但是,在 GNU awk 4.0+ 中,您可以使用
PROCINFO["sorted_in"]
to control the enumeration order)。
这里有一个更简单的解决方案,但是:
- 仅使用 POSIX awk 功能。
- 按照输入中遇到的顺序列出 IP 地址。
它基于 OP 命令的略微简化版本。
awk '/Invalid user/ { print ", " }' logfile | sort -t":" -k2,2 | uniq -c |
awk '
# Helper output function for printing an output line.
function printLine(c, n, l) {
sub(/,$/, "", n); print c, n l
}
# End of previous block found (new username)?
prevName != {
# Print summary line for previous block.
if (NR>1) printLine(count, prevName, ipList)
# Start new block.
prevName=; count=0; ipList=""
}
# Build block summary values.
{
count+=
ipList=ipList ", (" ") "
}
# Print summary line for last block.
END {
printLine(count, prevName, ipList)
}
'
我正在尝试以特定方式对日志文件进行排序,但我不确定如何执行最后一步。
我的日志文件有这样的条目:
Feb 15 17:00:34 server sshd[13879]: Invalid user test from 200.242.94.133
Feb 15 17:00:35 server sshd[13780]: Invalid user ftpuser from 200.242.94.133
Feb 15 17:01:34 server sshd[13890]: Invalid user test from 200.242.94.133
Feb 15 17:01:35 server sshd[13791]: Invalid user vnc from 200.242.94.133
Feb 15 17:01:35 server sshd[13794]: Invalid user test from 50.63.172.108
Feb 15 17:01:36 server sshd[13798]: Invalid user vnc from 50.63.172.108
我使用命令:
cat logfile | grep "Invalid user" | awk '{print ", " }' | sort -t":" -k2,2 | uniq -c
输出:
1 ftpuser, 200.242.94.133
2 test, 200.242.94.133
1 test, 50.63.172.108
1 vnc, 200.242.94.133
1 vnc, 50.63.172.108
我想得到:
1 ftpuser, (1) 200.242.94.133
3 test, (2) 200.242.94.133, (1) 50.63.172.108
2 vnc, (1) 200.242.94.133, (1) 50.63.172.108
我不确定如何对单词列求和,同时保持 ip 地址单独计数,然后将其与其他结果一起包含。
尝试回答:
# awk '/Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}' logfile | sort -k2
awk: /Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}
awk: ^ syntax error
awk: /Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}
awk: ^ syntax error
awk: /Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}
awk: ^ syntax error
$ awk '/Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}' logfile
2 vnc, (1) 50.63.172.108, (1) 200.242.94.133
1 ftpuser, (1) 200.242.94.133
3 test, (1) 50.63.172.108, (2) 200.242.94.133
如果您希望它按用户字母顺序排序:
$ awk '/Invalid user/{user[]++;ip[][]++} END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}' logfile | sort -k2
1 ftpuser, (1) 200.242.94.133
3 test, (1) 50.63.172.108, (2) 200.242.94.133
2 vnc, (1) 50.63.172.108, (1) 200.242.94.133
以上适用于 GNU awk
。我还没有用 BSD 测试过。
工作原理
/Invalid user/{user[]++;ip[][]++}
对于
logfile
中包含无效用户的任何行,这将计算用户名、字段 8 和 IP 地址、字段 10。END{for (u in user){printf "%s %s",user[u],u;for (i in ip[u])printf ", (%s) %s",ip[u][i],i;print""}}
当我们读完
logfile
后,循环遍历我们看到的每个用户并打印我们看到该用户的次数,然后是该用户的名字,然后是每个 ip地址,该 ip 的计数,后跟该 ip。
- 您正在使用 GNU awk(该解决方案使用非 POSIX 功能,不能与 BSD awk 一起使用(也用于 OS X) 或 mawk,例如)。
- 您不介意看似随机的 IP 地址顺序(由于关联数组的未排序键枚举;但是,在 GNU awk 4.0+ 中,您可以使用
PROCINFO["sorted_in"]
to control the enumeration order)。
这里有一个更简单的解决方案,但是:
- 仅使用 POSIX awk 功能。
- 按照输入中遇到的顺序列出 IP 地址。
它基于 OP 命令的略微简化版本。
awk '/Invalid user/ { print ", " }' logfile | sort -t":" -k2,2 | uniq -c |
awk '
# Helper output function for printing an output line.
function printLine(c, n, l) {
sub(/,$/, "", n); print c, n l
}
# End of previous block found (new username)?
prevName != {
# Print summary line for previous block.
if (NR>1) printLine(count, prevName, ipList)
# Start new block.
prevName=; count=0; ipList=""
}
# Build block summary values.
{
count+=
ipList=ipList ", (" ") "
}
# Print summary line for last block.
END {
printLine(count, prevName, ipList)
}
'