昨天下班前,老板給了一批LOG數據庫IP地址,需要統計LOG表里Message字段top 10的結果,並輸出到一個excel文件里。
抽查看了下,有兩種格式的以當天日期結尾的表名。由於數量太多,時間緊迫,只好寫批量腳本解決問題。
並以此擴展,解析其中的幾個常用shell程序,主體腳本寫在文章后半部分。
學習shell重在靈活運用命令,形成自己的思維方式,和書寫習慣,腳本參考即可。
解題過程步驟:
1.梳理IP地址及對應表名
2.確定查詢SQL
3.批量查詢數據
完整腳本附在文章最后
解析下常用到的知識點:
1.日期:關於日期結尾的表,表中涉及日期時間的表字段
注意:shell中養成給日期定義變量的習慣。
<1>.當前日期時間及格式
DATE_MARK=`date +'%Y%m%d'` 結果:20161214
DATE_MARK=`date + '%Y-%m-%d %H:%M:%S'` 結果:2016-12-14 18:20:11
過去日期時間及格式
DATE_MARK=`date -d'1 day ago' +'%Y%m%d'` 結果:一天之前:20161213
DATE_MARK=`date -d'1 hour ago' +'%Y-%m-%d %H:%M:%S'` 結果:2016-12-14 17:20:11
修改-d' ' :7天之前:7 days ago 7小時之前:7 hours ago
表名:TB_NAME="LOG_${DATE_MARK}"
2.遍歷思想和循環及行的處理
<1>.批量遠程執行命令,批量Telnet端口,批量ping主機
<2>.遍歷文件中每一行,進行添加,截取,輸出操作。
主體思想:先讀取ip或行,再處理ip或行,再利用ip或行
實例:
1.依次輸出文件中的每一行
命令行while循環遍歷: cat ip.txt | while read line; do echo $line;done
命令行for 循環遍歷:for line in `cat ip.txt`;do echo $line;done
腳本中調用:ip.txt,然后循環遍歷. ip文件作為腳本的執行參數
#!/bin/sh
ipfile=$1
cat ${ipfile}|while read line
do
echo ${line}
done
腳本執行:./xx.sh ip.txt
2.對行的處理,一行有多個分割字段時需要處理
格式:172.21.1.1,3306
截取一行的第一列IP:
IP=`echo ${line}|awk -F',' '{print $1}'`
PORT=`echo ${line}|awk -F',' '{print $2}'`
awk -F',' '{print $1}' 等同於 cut -f1 -d','
添加內容:
echo "${IP}_${PORT}:OK" 結果:172.21.1.1_3306:OK
3.關於自定義函數
<1>.不傳參函數:
fun_name()
{
name='Kata'
echo "My name is ${name}."
}
fun_name #調用方式,直接將:My name is Kata.輸出到屏幕
<2>.傳參函數
fun_name()
{
name=$1
echo "My name is ${name}."
}
fun_name "Alias" #調用方式,直接將:My name is Alias.輸出到屏幕
<3>.多參函數
fun_name()
{
name=$1
age=$2
echo "My name is ${name} and My age is ${age}."
}
fun_name "Sunny" "18" #調用方式,直接將:My name is Sunny and My age is 18.輸出到屏幕
<4>.將函數結果賦值給變量
status=`fun_name "Alias"` #變量status的內容就是:My name is Alias. 此時再將status變量應用到其它程序調用
<5>.自定義函數事例:統計IP數據庫里對應的表格式是哪種?
思路:選一種格式表作為判斷,存在做標記,不存在就是另一種。前提條件:每個ip上只存在一種表,避免意外兩種表都試試
FUN_CHECK()
{
ip=$1 #自定義函數傳參
tb_like=$2
MYSQL_CMD="/usr/local/mysql/bin/mysql -uadmin -padmin -h${ip} -P3306" #變量只有IP,端口也可定義變量
SQL="SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='LogDB' AND TABLE_NAME
= '${tb_like}_${DATE_MARK}';"
STATUS=`${MYSQL_CMD} -NBe"${SQL}"` #查詢數據庫表結果賦值給變量
if [ ${STATUS} == '1' ];then
echo ${ip}
else
echo #此處輸出空行或者去掉else,可方便將屏幕ip列表復制。甚至不要if判斷,直接:echo "${ip}:${STATUS}" 再篩選。
fi
}
在while循環中調用函數:
#!/bin/sh
.
.
.
cat $IP_FILE1|while read line
do
IP=`echo $line|cur -f1 -d' '`
FUN_CHECK "${IP}" "HA_Logging" #手動修改下第二個參數,另一個表也測試下,別遺漏ip。
done
4.關於輸出文件
將n個ip上表的查詢數據追加到一個excel里。SQL的查詢結果不要帶表頭。否則文件里會出現多個表頭行。
通過mysql命令指定NBe參數,只輸出數據結果,不顯示字段名。
mysql -u -p -h -P -NBe"${sql}"
5.腳本傳參和函數傳參
腳本的開頭定義:xxx=$1 xxx=$2
函數的開頭定義:xxx=$1 xxx=$2
腳本執行:./x.sh 參數1 參數2
函數調用:fun_name "參數1" "參數2"
附件見下面:
附件腳本1:梳理ip列表,及對應哪種表格式
說明:
腳本執行:執行兩次
./check_ip.sh ip.txt 'HA_Logging'
./check_ip.sh ip.txt 'LOG'
腳本第二個參數:作為表格式模糊查詢的變量傳參
cat check_ip.sh
#!/bin/sh
IPFILE=$1
TB_LIKE=$2
DATE_MARK=`date -d'1 day ago' +'%Y%m%d'`
FUN_CHECK()
{
ip=$1 #自定義函數傳參:ip
tb_like=$2 #自定義函數傳參:HA_Logging或者LOG
MYSQL_CMD="/usr/local/mysql/bin/mysql -uadmin -padmin -h${ip} -P3306" #變量只有IP,端口也可定義變量
SQL="SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='LogDB' AND TABLE_NAME
= '${tb_like}_${DATE_MARK}';"
STATUS=`${MYSQL_CMD} -NBe"${SQL}"` #查詢數據庫表結果賦值給變量
if [ ${STATUS} == '1' ];then
echo ${ip}
fi #此處定義 如果存在直接輸出ip,不存在,就不管。
}
cat ${IPFILE}|while read line
do
IP=`echo ${line}|cut -f1 -d' '`
FUN_CHECK "${IP}" "${TB_LIKE}"
done
附件腳本3:查詢表數據導入Excel
說明:為了一次性執行,將兩個ip列表文件作為腳本參數
腳本執行:./check_loginfo.sh ha_ip.txt log_ip.txt
cat check_loginfo.sh
#!/bin/sh
IP_FILE1=$1
IP_fILE2=$2
# 定義日期標志 : 20161214 (此處是昨天日期)
TIME_MARK=`date -d'1 day ago' +'%Y%m%d'`
# 定義表的名字:以日期結尾的表名 <DB_NAME.TB_NAME_20161214>
HA_TB="LogDB.HA_Logging_${TIME_MARK}"
LO_TB="LogDB.LOG_${TIME_MARK}"
# 對表查詢結果輸出到Excel文件:OUT FILE
OUT_FILE="/data/${TIME_MARK}_log.xls"
# 定義通用函數,從表里查詢數據結果
GET_INFO()
{
ipfile=$1
tbname=$2
cat $ipfile|while read line
do
IP=`echo $line|awk -F' ' '{print $1}'`
MYSQL_CMD="/usr/local/mysql/bin/mysql -uadmin -padmin -h${IP} -P9306"
SQL="SELECT ServiceName,LoggerName,COUNT(LoggerName) AS count_num FROM ${tbname} GROUP BY LoggerName ORDER BY count_num DESC LIMIT 10;"
$MYSQL_CMD -NBe"${SQL}" >>${OUT_FILE}
echo "$IP:ok"
done
}
# 執行調用
#
GET_INFO "${IP_FILE1}" "${HA_TB}"
GET_INFO "${IP_fILE2}" "${LO_TB}"
完結!