shell進階教程
阿新 • • 發佈:2017-08-07
ear 表名 常用 操作 har 要求 nic 情況 ugc
背景:就自己常用的shell腳本寫作風格,總結了一些知識點。也是作為交接工作的一部分文檔。部分內容單獨寫
#!/bin/sh # shell腳本進階教程 # 1.常用知識點:變量設置/日期設置/格式化輸出/定義函數/函數傳參/腳步傳參/變量的嵌套和叠代 # 2.常用環境:/數據庫監控/本地日誌監控/批量處理/定期獲取表數據/備份 # 3.常用循環:for/while # 4.常用命令:sed/cut/awk/ # 5.crontab 計劃任務 # 第一部分:常用知識點 # 1.【變量設置及變量替換】 # 1.1 全局變量和局部變量-在腳本中的位置來區分 # 全局變量: 腳本中直接定義 # 局部變量: 在循環語句中/自定義函數中 # 從位置順序上來說: # 全局變量:一般在腳本的開頭位置,先設置好;或者是在函數定義/循環語句之前先定義。 # 局部變量:用於局部的調用,比如循環語句中/自定義函數裏;循環或函數之外調用是不生效的 # 1.2 恒定變量和動態變量-變量的值是否變化 # 格式: # 恒定變量:eg: xxx=‘‘ 或者 xxx=" " 或者 或者 xxx=120 (數字或者端口的定義不用引號) 或者 xxx=" ‘‘ " 錯誤格式:相同引號不能套用xxx="""" # 動態變量:eg: xxx=`` 反引號:鍵盤上數字1 左邊的鍵 # 動態變量,兩種常用設置: # xxx=`shell命令` :直接把shell命令的結果賦值給xxx (xxx=`cat /data/a.txt|grep ‘3306‘` 將含有3306的行直接賦值給xxx變量) # xxx=`$cmd` : cmd="hello world" (將cmd變量的內容賦值給xxx,cmd可以是恒定變量也可以是動態變量) # 單引號和雙引號和多個引號的區別: # 單引號:是完全引用:舉兩個例子: # 1. \n :回車的意思 \t:是tab空格的意思 定義:str1=‘hello world!\nhello world!‘ 輸出結果: hello world!\nhello world! 原樣輸出 # 2.定義SQL語句:sql1=‘select * from db1.tb1 where name="joho" and time>"$start_time"‘ 由於是原樣輸出 start_time變量不會成功替換 # 雙引號:輸出字面值 但是特殊字符除外:比如轉義字符:\t \r \n 變量替換:$ # 1.定義:str2="hello world!\nhello world!" 輸出兩行 # 2.sql2="select * from db1.tb1 where name=‘joho‘ and time>‘$start_time‘" 正確! 時間必須引號引起來。 # 多個引號(單引號或雙引號):使用環境:定義的變量裏面有:單引號,雙引號,變量替換以及反引號 # 我使用過的唯一的例子:批量建表時: # seg01:批量打印建表語句00~99,不是很常用 for i in seq `0 99` do num=`printf "%02d" $i` #格式化0~9 變成:00~09 (兩位數字) sql="""create table `BLDB`.`log_message_‘‘‘$num‘‘‘`( `id` int, `name` varchar(10), primary key(id) )engine=innodb; """ # 之所以引用3個雙引號是因為 :SQLyog工具導出的語句的 庫名,表名,字段名 都用反引號引著。 # 3個引號裏面的變量替換,必須用3個單引號引,才能生效。 # 手動把反引號去掉 可以不用3個雙引號的。 done # 變量例子: user=‘admin‘ paswd=‘pssword‘ host=‘172.2.1.1‘ port=3306 dir1=‘/data/scripts‘ file1="${dir1}/log.txt" # 常用的變量替換 DateMark=`date ‘+%Y-%m-%d %H:%M:%S‘` # 動態變量設置當前的時間變量:2017-08-06 22:09:00 # 2.【日期/時間設置】 # 帶日期的表名/表中時間字段/腳本中的時間標誌 # 時間日期的分類:當前時間/n分鐘之前/n小時之前/n分鐘之內/ # 時間的格式化:%Y:年 %m:月 %d:天 %H:小時 %M:分鐘 %S:秒 # 2.1 當前時間: NowTime=`date ‘+%Y-%m-%d %H:%M:%S‘` #2017-08-06 22:09:00 NowTime=`date ‘+%Y%m%d %H%M%S‘` #20170806 220900 # 2.2 n分鐘之前: n minute ago /n day ago BeforeTime=`date -d‘2 minute ago‘ ‘+%Y-%m-%d %H:%M:%S‘` # 2.3 時間範圍:最近5分鐘 # 無論什麽環境,當前時間不計算,因為當前一分鐘是不完整的 # 用於sql查詢條件中時間字段的限制:格式的樣式要與表中格式一致 StartTime=`date -d‘1 minute ago‘ ‘+%Y-%m-%d %H:%M:%S‘` EndTime=`date -d‘5 minute ago‘ ‘+%Y-%m-%d %H:%M:%S‘` # 2.4 表名:BLDB.LOG_MESSAGE_20170806 # TB_MARK=`date ‘+%Y%m%d‘` # 20170806 TB_NAME="BLDB.LOG_MESSAGE_`date ‘+%Y%m%d‘`" # 1.直接寫入 : 不建議使用 TB_NAME="BLDB.LOG_MESSAGE_${TB_MARK}" # 2.變量替換 :最常用:易於隨時修改 # 2.5 腳步中的時間標誌 # echo "[${NowTime}] : Succeeded!" #執行命令後 打印輸出結果 # 3.【格式化輸出】: # 好處: # 1.輸出的規範要求,比如:00~09 而不是0~9;浮點型位數要求:一般用於建100張表 # 2.左右對齊:輸出美觀要求,行列對齊 便於查看結果 # 常用的3中:數值/字符/浮點數 # 數值 #seg02: for i in `seq 0 9` do printf "%02d" "$i" # 輸出2位,不夠用0補齊,格式化後直接打印輸出 done # 字符串 printf "%10s %s" "hello!" "it‘s a dog!" # 輸出兩個字段,第一個字段占10個字符,默認右對齊,不夠左側空格補齊 printf "%-10s %s" "hello!" "it‘s a dog!" # -:左對齊,右側空格 # 浮點數 num=98.2245 printf "%2.2f" "$num" # 格式化:小數點左側2位,右側保留2位。 用於成功率/百分比 # 4. 【定義函數】 # 4.1 常規函數(無傳參) #定義格式: GET_INFO() { NAME=‘Jhon‘ echo "My name is ${NAME}" } # 函數調用方式:直接調用函數名 # 直接腳本中寫函數名 GET_INFO #seg03 :完整腳本 vim getinfo.sh #-------------------------------(虛線是無用的) #!/bin/sh #shell腳本的開頭設置 # def:function GET_INFO() { NAME=‘Jhon‘ echo "My name is ${NAME}" } # excute: function GET_INFO #------------------------------- # 執行腳本及輸出內容 ./getinfo.sh My name is jhon # 4.2 定義傳參函數: # 定義格式:帶有2個參數的函數 # FUNCTION: GET_INFO() { PORT=$1 IP=$2 echo "MYSQL PORT IS : ${PORT} AND MySQL HOST IS ${IP}" result=`mysql -uadmin -p‘password‘ -h${IP} -P${PORT} -NBe"SELECT * FROM URCS_BLDB.LOG_MESSAGE_01;"` # 讀取表數據,將輸出結果賦值給result變量 echo "$result" >> /data/log.txt #將結果寫入指定文件 } # 調用方式:函數名 參數1 參數2 GET_INFO 3306 ‘172.21.1.1‘ GET_INFO 3307 ‘172.21.1.2‘ # 以上是兩次調用函數。適用於相似的結果輸出,不同的傳入變量 # 通常函數傳參 和腳本傳參 相結合 做監控項時 非常給力。現網監控就是如此做的 # 5. 【腳本傳參】 # 環境:使用一個腳本,處理相似的操作類。比如:不同MySQL用端口來區分,每個MySQL監控項是一樣的。唯一不同的是端口,因此端口就可以作為變量,作為腳本的參數 # 腳本調用方式:1個腳本參數 ./getinfo.sh 3306 # 腳本中的所有輸出內容都是3306數據庫相關的 ./getinfo.sh 3307 # 腳本中的所有輸出內容都是3307數據庫相關的 # 腳本參數在腳本中的體現 # 腳本開頭位置,設置腳本參數變量 db_port=$1 # $1 代表腳本後面的第一個參數;$2 代表腳本後面跟的第二個參數;$0 代表腳本本身 # 這種變量賦值,是將 腳本參數原樣的賦值給:db_port。腳本中就可以直接引用db_port 這個變量來代表端口。 # 如果是字符串作為腳本參數,字符串裏有特殊符號或者空格,需要用單引號 引起來。 #seg04: 腳本通過傳入端口,來監控該數據庫實例的 某個監控項 #!/bin/sh db_port=$1 db_item=$2 # 代表監控項:比如 連接數,主從狀態。。。。;可以看做是一個觸發動作,後面會講,總之這個是變化的量 echo "$db_port : $db_item" # 執行方式:./getinfo.sh 3306 conn # 輸出結果:3306 :conn # 6. 【腳本變量的嵌套】 # 6.1 常規的 嵌套 # seg05: #!/bin/sh # SQL查詢的where條件 S1=‘timeout‘ S2=‘error code‘ ...... # 定義函數:根據傳入的條件生成SQL語句;將語句賦值給一個變量,並將變量傳入另一個SQL查詢函數中,將查詢結果返回或者寫入文件 CREATE_SQL() { S=$1 SQL=‘‘‘SELECT * FROM URCS_BLDB.LOG_MESSAGE_01 WHERE message like "%‘‘‘$S‘‘‘%" ;‘‘‘ # 關於引號的使用,目的是生成的SQL是正常就行。 echo $SQL } # 定義SQL查詢函數 GET_INFO() { sql=$1 mysql -uadmin -p‘pasd‘ -h172.21.1.1 -P3306 -NBe"$sql"; } SQL1=`CREATE_SQL "$S1"` # 通過函數生成SQL語句,賦值給變量SQL1 SQL1_DATA=`GET_INFO "$SQL1"` #傳入SQL1,函數產生查詢結果,並賦值給SQL1_DATA變量。 echo $SQL1_DATA >SQL1.txt # 將變量內容寫入文件中 # 第二部分 # 常用環境 # 1. 【數據庫性能參數監控】 # 監控腳本思路: # (1).監控項很多,避免每次都訪問數據庫,因此,通過:show global status\G 將結果寫入一個文件 # (2).每個監控項,定義一個函數,從文件讀取信息,經過處理返回 # (3).通過腳本傳參的方式 觸發函數並返回值 ./xxx.sh action # (4).多實例情況,通過端口來區分,復用腳本。通過腳本傳參來實現:./xxx.sh port action # (5).有n個監控項,一分鐘會觸發腳本n次。 只需在第一次觸發時,就生成文件。因此需要定義函數,將status信息寫入文件,並檢查,文件是否存在,存在跳過,不存在,讀取信息並寫入。 # (6).生成文件以時間標誌,因此需要清理機制。定義一個清理函數作為監控項,在zabbix中每隔30分鐘調用一次。 # 簡寫腳本:主從狀態的監控 # seg06: #!/bin/sh #. /etc/profile #. /etc/bashrc # name : slave.sh ############# # 定義MySQL命令 變量: MYSQL_BIN="/usr/local/mysql5715/bin/mysql -umonitor -pmonitor" # 定義生成文件的時間標誌 INFO_TIME=`date +%m%d%H%M` # 定義輸出文件目錄 INFO_DIR="/usr/local/zabbix/scripts/tmp/" # 定義MySQL的端口 MYSQL_PORT="$1" # 定義生成的文件名 INFO_FILE="/usr/local/zabbix/scripts/tmp/SLAVE_INFO_${MYSQL_PORT}_${INFO_TIME}" ############# # 定義函數,判斷文件是否存在,不存在,獲取slave信息,並寫入文件;存在就跳過 GET_INFO(){ if [[ -f ${INFO_FILE} ]] ; then break else ${MYSQL_BIN} -S /data/socket/mysql${MYSQL_PORT}.sock -e ‘SHOW SLAVE STATUS \G‘ >${INFO_FILE} fi } # 定義從庫延時函數 Seconds_Behind_Master(){ SBM=`/bin/egrep -w ‘Seconds_Behind_Master‘ ${INFO_FILE} | awk ‘{print $2}‘ ` echo ${SBM} } # 定義SQL線程狀態 Slave_SQL_Running(){ THD_SQL=`/bin/egrep -w ‘Slave_SQL_Running‘ ${INFO_FILE} | awk ‘{print $2}‘ ` if [[ ${THD_SQL} = ‘No‘ ]] ; then echo 0 else echo 1 fi } # 定義IO線程狀態 Slave_IO_Running(){ THD_IO=`/bin/egrep -w ‘Slave_IO_Running‘ ${INFO_FILE} | awk ‘{print $2}‘ ` if [[ ${THD_IO} = ‘No‘ ]] ; then echo 0 else echo 1 fi } # 定義函數 判斷是主還是從 R_EMLP(){ RMLP=`/bin/egrep -w ‘Read_Master_Log_Pos‘ ${INFO_FILE} | awk ‘{print $2}‘ ` EMLP=`/bin/egrep -w ‘Exec_Master_Log_Pos‘ ${INFO_FILE} | awk ‘{print $2}‘ ` R_EMLP=$[${RMLP}-${EMLP}] echo ${R_EMLP} } ####################### GET_INFO # 每次執行腳本都觸發:獲取信息的函數 # 下面兩個變量 如果=4,說明是主庫,返回值:3,zabbix判斷認為是主,不會觸發報警 RMLP=`/bin/egrep -w ‘Read_Master_Log_Pos‘ ${INFO_FILE} | awk ‘{print $2}‘ ` RELP=`/bin/egrep -w ‘Relay_Log_Pos‘ ${INFO_FILE} | awk ‘{print $2}‘ ` # 下面的:case $2 in ,通過判斷腳本傳的第二個參數,是哪個,就觸發對應的函數,並返回對應的值 if [[ ${RMLP} == 4 ]] && [[ ${RELP} == 4 ]] ; then case $2 in sla_sbm) echo 3 ;; thd_sql) echo 3 ;; thd_io) echo 3 ;; sla_rem) echo 3 ;; *) esac else case $2 in sla_sbm) Seconds_Behind_Master ;; thd_sql) Slave_SQL_Running ;; thd_io) Slave_IO_Running ;; sla_rem) R_EMLP ;; *) esac fi # 定義清理函數 # 定義清理函數:每隔30分鐘清理一次,每次把前一分鐘之前的都清理掉 GLO_CLEAR(){ /bin/find ${INFO_DIR}/*_INFO_* -ctime -1 | xargs rm -f FILE_NUM=`/bin/find ${INFO_DIR} -name "*_INFO_*" -ctime -1 | wc -l` if [[ ${FILE_NUM} == 0 ]] ; then echo 1 else echo 0 fi } #測試:./slave.sh 3306 thd_sql 會得到一個返回值 # 2.【本地log日誌,關鍵字查詢】 # SQL查詢本地數據庫表,含有錯誤關鍵字的行總數, # 腳本思路 # (1).錯誤關鍵字 查詢多,以標準格式,放到單獨的文件裏。腳本通過循環讀取該文件,進行SQL生成 # (2).SQL 查詢的結果,存放到對應的文件 # (3).輸出信息中字段條件多,所以通過其它腳本處理該信息 # (4). # 簡寫腳本 #!/bin/sh # 定義變量 HOST="localhost" PORT=9306 USER="root" PSWD="root" DB_NAME="LogDB" TB_NAME="LOG_"`date +‘%Y%m%d‘` MYSQL_CMD="/home/mysql/Percona-Server/bin/mysql -u${USER} -p${PSWD} -h${HOST} -P${PORT} -S /tmp/mysql.sock" # 時間變量設置,取值範圍前一分鐘的數據 TIME0=`date +‘%Y-%m-%d %H:%M‘` # 當前時間 TIME1=`date -d "1 minutes ago" +‘%Y-%m-%d %H:%M‘` # 前一分鐘:2017-08-05 10:34 秒鐘在SQL定義時添加 # 定義結果的輸出文件的目錄: # tmp_dir FILE_DIR="/data/scripts/shelldir" # 定義錯誤關鍵字的格式 文件 KeyFile=‘/data/scripts/KeyFile.txt‘ 內容: ####too many connections####connect.txt#### ####timeout####timeout.txt#### #定義SQL生成函數:參數:關鍵字 GET_SQL() { Key=$1 SQL=‘‘‘SELECT A.ServiceName,IFNULL(B.count_error,0) AS count_total FROM (select distinct(ServiceName) from ‘‘‘${DB_NAME}.${TB_NAME}‘‘‘ where (Time >="‘‘‘${TIME1}‘:00‘‘‘‘" AND Time<="‘‘‘${TIME0}‘:59‘‘‘‘")) AS A left join (select ServiceName,count(*) AS count_error from ‘‘‘${DB_NAME}.${TB_MARK}‘‘‘ WHERE (Time >="‘‘‘${TIME1}‘:00‘‘‘‘" AND Time <="‘‘‘${TIME1}‘:59‘‘‘‘") AND (Message LIKE "%‘‘‘${Key}‘‘‘%" OR Error LIKE "%‘‘‘${Key}‘‘‘%") group by ServiceName) AS B ON A.ServiceName=B.ServiceName group by A.ServiceName;‘‘‘ echo $SQL } # 定義SQL查詢函數:參數:SQL語句,文件名 GET_INFO() { SQL=$1 FILE=$2 ${MYSQL_CMD} -NBe "${SQL}" >>${FILE_DIR}/${FILE} } # 循環讀取關鍵字文件,一次進行SQL生成,SQL查詢 # 主程序 cat ${KeyFile}| while read line do # 截取關鍵字和輸出文件名字 Key=`echo ${line}|awk -F‘####‘ ‘{print $1}‘` Outfile=`echo ${line}|awk -F‘####‘ ‘{print $2}‘` # 生成SQL語句 SQL=`GET_SQL "$Key"` # 查詢結果寫入文件 GET_INFO "$SQL" "$Outfile" done # 3.【批量處理】 # 常用 for i in `seq 0 99` do echo "truncate table xxxx_$i" done #命令行:for i in `seq 1 100`;do echo "truncate table xxxx_$i;";done # 4種批量建表程序 ##create 100 tables #!/bin/sh # db_name=‘USE RenmaiInfluenceDB‘ for i in {0 99}; do len=`expr length $i` if [ $len -eq 2 ];then num=$i else num="0${i}" fi echo ‘‘‘ CREATE TABLE `logRegister_‘‘‘$num‘‘‘` ( `Id` int(10) NOT NULL AUTO_INCREMENT COMMENT ‘自增id‘, `AwardId` int(10) NOT NULL COMMENT ‘獎品Id‘, `UserId` int(10) NOT NULL COMMENT ‘中獎用戶‘, `CourierName` varchar(20) DEFAULT NULL COMMENT ‘快遞名‘, `CourierNumber` varchar(40) DEFAULT NULL COMMENT ‘運單號‘, `CreateDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ‘中獎時間‘, PRIMARY KEY (`Id`), KEY `IX_SignLotteryWinner_UserId_CreateDate` (`UserId`,`CreateDate`) ) ENGINE=InnoDB AUTO_INCREMENT=1602 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT=‘打卡中獎表‘; ‘‘‘ echo done ======================================================================================================== #!/bin/sh #creat tables for i in `seq 1 15` do var=`printf "%02d\n" $i` echo ‘‘‘ CREATE TABLE `logRegister_‘‘‘$var‘‘‘` ( `Id` int(10) NOT NULL AUTO_INCREMENT COMMENT ‘自增id‘, `AwardId` int(10) NOT NULL COMMENT ‘獎品Id‘, `UserId` int(10) NOT NULL COMMENT ‘中獎用戶‘, `CourierName` varchar(20) DEFAULT NULL COMMENT ‘快遞名‘, `CourierNumber` varchar(40) DEFAULT NULL COMMENT ‘運單號‘, `CreateDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ‘中獎時間‘, PRIMARY KEY (`Id`), KEY `IX_SignLotteryWinner_UserId_CreateDate` (`UserId`,`CreateDate`) ) ENGINE=InnoDB AUTO_INCREMENT=1602 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT=‘打卡中獎表‘; ‘‘‘ echo done ============================================================================ #!/bin/sh # 需要將 SQL 中的" ` " 符號刪除 for i in `seq 0 1 99` do STEP=`printf %02d ${i}` create_tab_sql=" CREATE TABLE logRegister_${STEP} ( Id int(11) NOT NULL AUTO_INCREMENT COMMENT ‘表id‘, UserId int(11) NOT NULL COMMENT ‘用戶id‘, UserName varchar(32) COLLATE utf8_unicode_ci NOT NULL COMMENT ‘用戶名‘, LotteryNumber tinyint(1) NOT NULL COMMENT ‘今日剩余可抽獎次數‘, StateTime date NOT NULL COMMENT ‘當前日期‘, lottery tinyint(1) NOT NULL DEFAULT ‘0‘, award_times tinyint(1) NOT NULL DEFAULT ‘0‘, FeitionID int(11) DEFAULT NULL COMMENT ‘用戶飛信號碼‘, PRIMARY KEY (Id), KEY idx (UserId) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT=‘每日用戶可遊戲次數紀錄表‘;" echo -e ${create_tab_sql} echo done =================================================================================== #!/usr/bin/python import string for i in range(7,13): sql = "CREATE TABLE `UgcFeedContent_2015%02d` LIKE `UgcFeedContent_201503`;" % i print(sql) for i in range(1,13): sql = "CREATE TABLE `UgcFeedContent_2016%02d` LIKE `UgcFeedContent_201503`;" % i print(sql) ======================================== 其余幾部分 單獨寫
shell進階教程