替代 uniq -c 并在纯 awk 中排序
Alternative to uniq -c and sort in pure awk
这是一个命令,用于从 access.log 文件中按 IP 地址过滤出命中数,然后计算每个 IP 的命中数,并将它们从低到高排序:
awk '{print }' "${ACCESSLOG}" | sort -n | uniq -c | sort -nk1
这里是结果的摘录:
26 45.59.193.115
26 74.125.63.33
27 88.156.36.194
28 12.208.4.156
29 12.208.4.156
31 98.236.117.199
32 176.9.82.6
33 187.34.167.111
35 67.110.83.252
37 54.184.4.183
39 195.59.2.173
39 70.199.109.118
44 12.208.4.156
59 88.156.36.194
现在只使用 awk 是否可以得到相同的结果?
没有 uniq -c,没有排序。
似乎在网上找不到太多关于此的信息...
理论上 - 是的,你可以。但是这里有两部分:
你能实现sort和uniq吗?排序将非常棘手,但可以肯定的是,您可以在 awk 中实现任何东西。 Uniq 应该是微不足道的。
你能实施你的管道吗,所以 | uniq -c | sort -nk1 | uniq
。是的,这不会很难。只需使用类似:
awk '{ips[]++} END {for (ip in ips) { print ips[ip], ip}}'
这就是计数/唯一性部分。您必须添加 asort
以在末尾对条目进行排序。
GNU awk 具有使计数和排序变得容易的功能:
awk 'BEGIN{PROCINFO["sorted_in"]="@val_num_asc"} { a[]++ } END{for (ip in a)print a[ip],ip}' access.log
语句 PROCINFO["sorted_in"]="@val_num_asc"
使数组根据值而不是键按数字升序排列。
(Mac OSX 上的默认 awk 是 BSD,所以不要在那里尝试。)
例子
假设我们有输入文件:
$ cat access.log
74.125.63.33
45.59.193.115
45.59.193.115
74.125.63.33
74.125.63.33
74.125.63.33
195.59.2.173
然后以上产生:
$ awk 'BEGIN{PROCINFO["sorted_in"]="@val_num_asc"} { a[]++ } END{for (ip in a)print a[ip],ip}' access.log
1 195.59.2.173
2 45.59.193.115
4 74.125.63.33
@viraptor 实际上,我更正了我的命令,因为我们的结果不同,现在看起来更像这样:
awk '{print }' "${ACCESSLOG}" | sort -n | uniq -c | sort -nk1
实际 0m0.020s
用户 0m0.016s
sys 0m0.012s
所以我将 sort 命令添加到你最初的提议中,因为我既不能使用 gawk (asort) 也不能使用 GNU:
awk '{if(ips[]) {ips[]++} else {ips[]=1}} END {for (ip in ips) { print ips[ip], ip}}' "$ACCESSLOG" | sort -nk1
实际 0m0.019s
用户 0m0.004s
sys 0m0.008s
而您的重构命令:
awk '{ips[]++} END {for (ip in ips) { print ips[ip], ip}}' "${ACCESSLOG}" | sort -nk1
实际 0m0.014s
用户 0m0.004s
sys 0m0.012s
比较速度很有趣...
这是一个命令,用于从 access.log 文件中按 IP 地址过滤出命中数,然后计算每个 IP 的命中数,并将它们从低到高排序:
awk '{print }' "${ACCESSLOG}" | sort -n | uniq -c | sort -nk1
这里是结果的摘录:
26 45.59.193.115
26 74.125.63.33
27 88.156.36.194
28 12.208.4.156
29 12.208.4.156
31 98.236.117.199
32 176.9.82.6
33 187.34.167.111
35 67.110.83.252
37 54.184.4.183
39 195.59.2.173
39 70.199.109.118
44 12.208.4.156
59 88.156.36.194
现在只使用 awk 是否可以得到相同的结果? 没有 uniq -c,没有排序。
似乎在网上找不到太多关于此的信息...
理论上 - 是的,你可以。但是这里有两部分:
你能实现sort和uniq吗?排序将非常棘手,但可以肯定的是,您可以在 awk 中实现任何东西。 Uniq 应该是微不足道的。
你能实施你的管道吗,所以 | uniq -c | sort -nk1 | uniq
。是的,这不会很难。只需使用类似:
awk '{ips[]++} END {for (ip in ips) { print ips[ip], ip}}'
这就是计数/唯一性部分。您必须添加 asort
以在末尾对条目进行排序。
GNU awk 具有使计数和排序变得容易的功能:
awk 'BEGIN{PROCINFO["sorted_in"]="@val_num_asc"} { a[]++ } END{for (ip in a)print a[ip],ip}' access.log
语句 PROCINFO["sorted_in"]="@val_num_asc"
使数组根据值而不是键按数字升序排列。
(Mac OSX 上的默认 awk 是 BSD,所以不要在那里尝试。)
例子
假设我们有输入文件:
$ cat access.log
74.125.63.33
45.59.193.115
45.59.193.115
74.125.63.33
74.125.63.33
74.125.63.33
195.59.2.173
然后以上产生:
$ awk 'BEGIN{PROCINFO["sorted_in"]="@val_num_asc"} { a[]++ } END{for (ip in a)print a[ip],ip}' access.log
1 195.59.2.173
2 45.59.193.115
4 74.125.63.33
@viraptor 实际上,我更正了我的命令,因为我们的结果不同,现在看起来更像这样:
awk '{print }' "${ACCESSLOG}" | sort -n | uniq -c | sort -nk1
实际 0m0.020s
用户 0m0.016s
sys 0m0.012s
所以我将 sort 命令添加到你最初的提议中,因为我既不能使用 gawk (asort) 也不能使用 GNU:
awk '{if(ips[]) {ips[]++} else {ips[]=1}} END {for (ip in ips) { print ips[ip], ip}}' "$ACCESSLOG" | sort -nk1
实际 0m0.019s
用户 0m0.004s
sys 0m0.008s
而您的重构命令:
awk '{ips[]++} END {for (ip in ips) { print ips[ip], ip}}' "${ACCESSLOG}" | sort -nk1
实际 0m0.014s
用户 0m0.004s
sys 0m0.012s
比较速度很有趣...