关于sed命令执行逻辑、awk用法及Bash数组判断的技术咨询
Nginx日志统计Bash脚本疑问解答
1. sed命令sed 's/.*\[//g;s/].*//g;s/:.*//g'处理过程
这条sed命令包含三个连续的替换操作,针对每行Nginx日志分步处理:
- 第一步:
s/.*\[//g:匹配从行首到左方括号[的所有内容(包括[),将其替换为空。以日志第一行为例,处理后得到16/Feb/2020:22:31:32 +0000]。 - 第二步:
s/].*//g:匹配右方括号]及后面的所有内容,替换为空。处理后得到16/Feb/2020:22:31:32 +0000。 - 第三步:
s/:.*//g:匹配第一个冒号:及后面的所有内容,替换为空。最终提取出日期部分16/Feb/2020。
2. awk '{print $1}'的作用
awk默认以空白字符(空格、制表符)为分隔符拆分每行内容,$1代表拆分后的第一个字段。在给定的Nginx日志格式中,每行第一个字段就是发起请求的客户端IP地址,所以这个命令的作用就是提取日志中的客户端IP。
3. if [[ -v day_array[$day] ]]的测试内容
-v是Bash的条件测试运算符,用于检查关联数组中指定键的元素是否存在。这条语句的作用是:测试关联数组day_array中是否已经存在以变量$day(即提取出的日期)为键的元素。如果存在,就将该元素的值加1(统计该日期的请求次数);如果不存在,就初始化该键对应的值为1,实现按天统计请求量的功能。
关于在线测试sed命令时无法读取文件的问题
你使用的在线sed工具仅支持直接输入文本内容进行测试,不支持读取本地文件。解决方法是将日志内容复制粘贴到工具的输入框中,再执行sed命令即可完成测试。
原始日志输入
172.19.0.100 - - [16/Feb/2020:22:31:32 +0000] "GET /site HTTP/1.1" 200 36565 "https://command-not-found.com/curl" "Mozilla/5.0+(compatible; UptimeRobot/2.0; http://www.uptimerobot.com/)" "172.19.0.3" 172.19.0.101 - - [16/Feb/2020:22:30:10 +0000] "GET /credits HTTP/1.1" 200 31067 "-" "Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)" "172.19.0.2" 172.19.0.102 - - [17/Feb/2020:22:30:10 +0000] "GET /index HTTP/1.1" 200 31067 "-" "Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)" "172.19.0.2" 172.19.0.100 - - [18/Feb/2020:22:35:10 +0000] "GET /index HTTP/1.1" 200 31067 "-" "Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)" "172.19.0.2"
原始Bash脚本
#!/usr/bin/env bash LOG_FILE="$1" function request_per_day() { declare -A day_array while read line; do day=$(echo "$line" | sed 's/.*\[//g;s/].*//g;s/:.*//g') if [[ -v day_array[$day] ]]; then day_array[$day]=$((day_array[$day]+1)) else day_array[$day]=1 fi done < $LOG_FILE for day in ${!day_array[@]}; do echo ${day_array[$day]} $day; done | sort -rn | head -10 } function request_per_ip() { declare -A ip_array while read line; do ip=$(echo $line | awk '{print $1}') if [[ -v ip_array[$ip] ]]; then ip_array[$ip]=$((ip_array[$ip]+1)) else ip_array[$ip]=1 fi done < $LOG_FILE for ip in ${!ip_array[@]}; do echo ${ip_array[$ip]} $ip; done | sort -rn | head -10 } request_per_day echo "" request_per_ip
内容的提问来源于stack exchange,提问作者Gifter Villanueva
相关产品推荐
相关产品推荐

