前言
最近就干了兩件有意思的事,昨天分享了一個,今天我們來分享另一個——shell
腳本統計數據。
相比於python
,shell
是另一種特別常用,特別實用,也特別基礎的腳本語言,基本上所有的linux
系統都支持shell
,更准確地說,shell
讓系統運行更方便,是shell
讓linux
更強大,所以學習一些基本的shell
語法,可以簡化linux
的運維工作,提升我們的工作效率。
其實,win
平台也是有它的shell
的,也就是bat
或者cmd
腳本,通過這些腳本,我們同樣也可以做很多事,等下我們也分享一些win
平台的常用腳本,讓各位小伙伴見識下腳本語言的魅力。
好了,廢話少說,下面我們開始編寫數據統計腳本。
shell腳本統計數據
在開始之前,我們先看下shell
的相關內容。shell
通俗來講就是我們通常說的CMD
(commond
,也叫命令行),通過shell
我們可以直接與操作系統內核進行溝通。
至於為什么叫shell
,也很好理解,shell
的中文名稱是殼,而kernel
是操作系統的核心,核心是需要和外側進行隔離的,通過什么來隔離呢,就是通過殼(shell
),而且shell
還要充當核心與外界溝通的信使。
當然shell
本身也有好多種:
/bin/sh
:已經被/bin/bash
所取代/bin/bash
:Linux
預設的shell
/bin/tcsh
:整合C shell
,提供更多的功能/bin/csh
:已經被/bin/tcsh
所取代/bin/zsh
:自動補全功能很強大,檢查拼寫功能很強大,因為oh-my-zsh
名聲大噪,而且可定制性比bash
更高
如果是日常使用的話,推薦實用zsh
,但是如果是寫腳本的話,建議用bash
,畢竟它是linux
的預裝shell
簡單介紹
下面是最簡單的shell
腳本:
#!/bin/bash
echo "hello shell"
結合我們上面shell
的相關知識,我們可以推測出第一行是標記shell
類別的,也就是用哪種shell
來解釋腳本;從第二行開始就是腳本的內容了。
運行這個腳本之后會在telminal
控制台打印輸出hello shell
字符串:
shell
腳本基本要點
-
linux
系統的shell
腳本文件后綴是.sh
,也就是shell
的簡寫。 -
shell
腳本的注釋方式是# 注釋內容
,linux
平台絕大多數的配置文件都是采用這種方式進行注釋的:#!/bin/bash # 我是腳本注釋 eacho "hello shell"
-
shell
腳本有兩種運行方式第一種是:
# 腳本名稱hello.sh
sh hello.sh
# 或者
bash hello.sh
第二種方式是:
./hello.sh
雖然這兩種方式都可以運行,但是第二種方式需要給腳本增加運行權限,具體命令如下:
chmod u+x hello.sh
u
表示所屬用戶,+x
表示增加運行權限,所以執行上面的這行命令,這個腳本就有了運行權限,然后再通過./hello.sh
運行即可。
關於sh
腳本的基礎知識我們就先分享這么多,想系統學習的小伙伴可以去看下《鳥叔的Linux
私房菜》,里面關於shell script
講的還是比較系統的,而且很全面,這本書也算是linux
的中文聖經了。
編寫統計腳本
下面這段腳本執行的操作很簡單,首先是查詢了db
庫配置庫,並將結果寫入到connect_info
文件中,拿到查詢結果之后,循環遍歷,然后再次組裝sql
查詢我們要統計的數據,並將數據寫入count_data
,之后我們就可以通過awk
、sort
、head
等命令對結果進行解析、排序,最終拿到我們想要的結果。
#!/bin/bash
# mysql數據庫配置信息
# 數據庫端口
port=3306
# 數據庫用戶名
user="root"
# 數據庫密碼
pawd="root"
# 數據庫地址
host="192.168.1.105"
# 庫名
db_name="exam_system"
# 查詢數據庫連接信息
select_sql="select id, db_server, db_source_name from db_config"
# 統計sql
count_sql="select count(*) from question_option_info where question_id in (select id from question_info where type = 5 ) and CHAR_LENGTH(title) >= 50"
# 命令行連接mysql,並執行sql,這里我將查詢結果輸出到connect_info文件中
mysql -h "${host}" -P "${post}" -u"${user}" -p"${pawd}" -D${db_name} -N -s -e "${select_sql}" >connect_info
# 循環遍歷
while read line
do
# 獲取連接信息中的數據
config_id=`echo "$line"|cut -f1`
db_server=`echo "$line"|cut -f2`
db_name=`echo "$line"|cut -f3`
#mysql -h "${db_server}" -P "${port}" -u"${user}" -p"${pawd}" -D${db_name} -N -s -e "${count_sql}">>count_data
result=`mysql -h "${host}" -P "${port}" -u"${user}" -p"${pawd}" -D${db_name} -N -s -e "${count_sql}"`
echo "${config_id} ${result}" >> count_data
done < connect_info
這里我們簡單解釋下這段腳本,4~16
行我們分別定義了7
個變量,sh
腳本定義變量的方式和python
有點像,都不需要指定數據類型;
mysql命令參數
18
行我們執行了一個mysql
的命令,這行命令的作用是連接mysql
並執行sql
語句,-e
表示執行並退出,后面直接跟sql
語句,會直接打印sql
,執行完成后會打印sql
結果:
我以前真不知道還有這種操作方式,不是這次統計數據,應該不會去了解。
-s
表示以制表符分割顯示結果,不加這個參數的話,結果會包括|
,也就是我們通常看到的結果:
不加-s
查詢結果如下:
加了-s
顯示結果如下:
-N
參數的作用是隱藏字段名稱,也就是title
(加上這個參數可以保證我們查詢結果只有數據):
sh腳本要點
在sh
腳本中,將運行結果輸出到文件中有兩種方式,一種是>
,另一種是>>
,兩者的區別是,前者會覆寫文件中的內容,而后者是在文件中追加(如果文件中已經存在內容,則會在原有內容后面追加新的內容),這種操縱在sh
中很普遍,比如:
# 將 ls 結果輸出到文件中
ls /home/syske > file_list
# 將當前時間輸出到文件中,每次追加
date >> date_list
<
與>
剛好相反,是將文件的內容讀取出來,比如:
# 讀取 date_list
cat < date_list
另外除了直接將命令結果輸出,我們還可以用變量接收運行結果:
result=`mysql -h "${host}" -P "${port}" -u"${user}" -p"${pawd}" -D${db_name} -N -s -e "${count_sql}"`
比如上面這行sh
代碼就是用result
接收mysql
的運行結果,需要注意的是命令必須通過( ` )進行包裝,否則命令無法運行。這種方式有個好處,就是可以對結果進行處理,比如拼接變量:
echo "${config_id} ${result}"
運行結果處理
拿到運行結果之后,我們可以通過awk
、sort
等命令進行處理,以拿到最終數據。比如我們的查詢結果如下:
Sun Nov 7 16:59:54 CST 2021
Sun Nov 7 16:59:57 CST 2021
Sun Nov 7 16:59:58 CST 2021
如果是通過awk
處理,則可以直接幫我們將數據分割成:sun
、Nov
、7
、16:59:54
、CST
、2021
這樣的格式,而且很簡單:
awk '{print $1, $2, $3, $4, $5, $6}' date_list
這里的$1
表示分割的第一部分,也就是Sun
,其他以此類推;$0
表示原始數據
排序的話,可以用sort
命令進行操作:
awk '{print $1, $2, $3, $4, $5, $6}' date_list | sort -rk 4
排序結果如下:
其中-r
表示降序排序,默認是正序排序,-k
表示按指定序列排序,4
表示按第四列排序,也就是按時間排序。更多其他排序可以參考sort
文檔。
最后再補充點akw
的常用操作命令:
- 求和
cat data|awk '{sum+=$1} END {print "Sum = ", sum}'
- 求平均
cat data|awk '{sum+=$1} END {print "Average = ", sum/NR}'
- 求最大值
cat data|awk 'BEGIN {max = 0} {if ($1>max) max=$1 fi} END {print "Max=", max}'
- 求最小值(min的初始值設置一個超大數即可)
awk 'BEGIN {min = 1999999} {if ($1<min) min=$1 fi} END {print "Min=", min}'
擴展知識
這里再分享win
環境下的幾個常用命令:
- 關機操作:
# 休眠操作
shutdown /h
# 重啟
shutdown /r
# 定時關閉(兩小時后關機,單位秒)
shutdown /s /t 3600
- 顯示指定文件夾下的所有內容,包括文件和子文件夾:
dir /b/s ./
- 顯示指定文件夾樹形結構:
tree ./
另外,我們前面說了,win
平台也支持>
和>>
,這樣我們就可以把上面命令的結果輸出到文件中:
dir /b/s ./ > file_list.log
tree ./ >> struts.log
-
批量修改文件后綴(文件名)
# 修改文件擴展名 ren *.gif *.jpg # 或者(ren和rename等同) rename *.gif *.jpg # 修改文件名 ren *.gif *-syske.gif
-
批量刪除文件
# 我經常通過這樣的方式刪除重復文件
del *(1).jpg
結語
shell
腳本統計數據的內容我們就分享這么多,核心知識點包括shell
的基本語法、linux
的常用命令等,總體的內容難點並不大,如果實際工作中遇到了類似的需求,各位小伙伴可以參考。
最后,還想多說兩句。在我的理解中,我覺得一切工具都可以變成生產力工具,最關鍵的還是要學會活學活用,養成一個善於動腦的小可愛,這樣才能避免低效重復工作,有時候同樣的工具,關鍵在於你如何用,你是否能夠發現它的價值點,現實中的栗子有很多,比如回形針的一百種用法。
當然,實際工作中也會遇到很多類似的問題,比如你現在需要修改一批線上數據(400
多條),數據的條件和更新內容各不相同,你能想到那些處理方式?通過編輯器批量修改?還是手工一條一條修改?還是借助其他工具,python
、excel
?上周五我就完成了這樣的工作,最終通過excel
生成update sql
,通過文本編輯器批量插入和替換拼接緩存key
,最后完成相關數據修改。我說這個例子是希望各位小伙伴在學習和實踐的時候,要學會發散思維,不要被當前的語言、環境、方法所局限,要學會解決問題,學會知識的橫向應用,橫向思考。好了,今天廢話有點多,各位小伙伴,晚安吧!