1. 程式人生 > >shell進階教程

shell進階教程

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進階教程