日常利器,shell腳本統(tǒng)計(jì)數(shù)據(jù)

前言
最近就干了兩件有意思的事,昨天分享了一個(gè),今天我們來(lái)分享另一個(gè)——shell腳本統(tǒng)計(jì)數(shù)據(jù)。
相比于python,shell是另一種特別常用,特別實(shí)用,也特別基礎(chǔ)的腳本語(yǔ)言,基本上所有的linux系統(tǒng)都支持shell,更準(zhǔn)確地說(shuō),shell讓系統(tǒng)運(yùn)行更方便,是shell讓linux更強(qiáng)大,所以學(xué)習(xí)一些基本的shell語(yǔ)法,可以簡(jiǎn)化linux的運(yùn)維工作,提升我們的工作效率。
其實(shí),win平臺(tái)也是有它的shell的,也就是bat或者cmd腳本,通過(guò)這些腳本,我們同樣也可以做很多事,等下我們也分享一些win平臺(tái)的常用腳本,讓各位小伙伴見(jiàn)識(shí)下腳本語(yǔ)言的魅力。
好了,廢話少說(shuō),下面我們開(kāi)始編寫(xiě)數(shù)據(jù)統(tǒng)計(jì)腳本。
shell腳本統(tǒng)計(jì)數(shù)據(jù)
在開(kāi)始之前,我們先看下shell的相關(guān)內(nèi)容。shell通俗來(lái)講就是我們通常說(shuō)的CMD(commond,也叫命令行),通過(guò)shell我們可以直接與操作系統(tǒng)內(nèi)核進(jìn)行溝通。
至于為什么叫shell,也很好理解,shell的中文名稱(chēng)是殼,而kernel是操作系統(tǒng)的核心,核心是需要和外側(cè)進(jìn)行隔離的,通過(guò)什么來(lái)隔離呢,就是通過(guò)殼(shell),而且shell還要充當(dāng)核心與外界溝通的信使。
當(dāng)然shell本身也有好多種:
/bin/sh:已經(jīng)被/bin/bash所取代/bin/bash:Linux預(yù)設(shè)的shell/bin/tcsh:整合C shell,提供更多的功能/bin/csh:已經(jīng)被/bin/tcsh所取代/bin/zsh:自動(dòng)補(bǔ)全功能很強(qiáng)大,檢查拼寫(xiě)功能很強(qiáng)大,因?yàn)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">oh-my-zsh名聲大噪,而且可定制性比bash更高
如果是日常使用的話,推薦使用zsh,但是如果是寫(xiě)腳本的話,建議用bash,畢竟它是linux的預(yù)裝shell
簡(jiǎn)單介紹
下面是最簡(jiǎn)單的shell腳本:
#!/bin/bash
echo?"hello?shell"
結(jié)合我們上面shell的相關(guān)知識(shí),我們可以推測(cè)出第一行是標(biāo)記shell類(lèi)別的,也就是用哪種shell來(lái)解釋腳本;從第二行開(kāi)始就是腳本的內(nèi)容了。
運(yùn)行這個(gè)腳本之后會(huì)在telminal控制臺(tái)打印輸出hello shell字符串:

shell腳本基本要點(diǎn)
linux系統(tǒng)的shell腳本文件后綴是.sh,也就是shell的簡(jiǎn)寫(xiě)。shell腳本的注釋方式是# 注釋內(nèi)容,linux平臺(tái)絕大多數(shù)的配置文件都是采用這種方式進(jìn)行注釋的:#!/bin/bash
#?我是腳本注釋
eacho?"hello?shell"shell腳本有兩種運(yùn)行方式第一種是:
#?腳本名稱(chēng)hello.sh
sh?hello.sh
#?或者
bash?hello.sh
第二種方式是:
./hello.sh
雖然這兩種方式都可以運(yùn)行,但是第二種方式需要給腳本增加運(yùn)行權(quán)限,具體命令如下:
chmod?u+x?hello.sh
u表示所屬用戶(hù),+x表示增加運(yùn)行權(quán)限,所以執(zhí)行上面的這行命令,這個(gè)腳本就有了運(yùn)行權(quán)限,然后再通過(guò)./hello.sh運(yùn)行即可。
關(guān)于sh腳本的基礎(chǔ)知識(shí)我們就先分享這么多,想系統(tǒng)學(xué)習(xí)的小伙伴可以去看下《鳥(niǎo)叔的Linux私房菜》,里面關(guān)于shell script講的還是比較系統(tǒng)的,而且很全面,這本書(shū)也算是linux的中文圣經(jīng)了。
編寫(xiě)統(tǒng)計(jì)腳本
下面這段腳本執(zhí)行的操作很簡(jiǎn)單,首先是查詢(xún)了db庫(kù)配置庫(kù),并將結(jié)果寫(xiě)入到connect_info文件中,拿到查詢(xún)結(jié)果之后,循環(huán)遍歷,然后再次組裝sql查詢(xún)我們要統(tǒng)計(jì)的數(shù)據(jù),并將數(shù)據(jù)寫(xiě)入count_data,之后我們就可以通過(guò)awk、sort、head等命令對(duì)結(jié)果進(jìn)行解析、排序,最終拿到我們想要的結(jié)果。
?#!/bin/bash
?#?mysql數(shù)據(jù)庫(kù)配置信息
?#?數(shù)據(jù)庫(kù)端口
?port=3306
?#?數(shù)據(jù)庫(kù)用戶(hù)名
?user="root"
?#?數(shù)據(jù)庫(kù)密碼
?pawd="root"
?#?數(shù)據(jù)庫(kù)地址
?host="192.168.1.105"
?#?庫(kù)名
?db_name="exam_system"
?#?查詢(xún)數(shù)據(jù)庫(kù)連接信息
?select_sql="select?id,?db_server,?db_source_name?from?db_config"
?#?統(tǒng)計(jì)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,并執(zhí)行sql,這里我將查詢(xún)結(jié)果輸出到connect_info文件中
?mysql?-h?"${host}"?-P?"${post}"?-u"${user}"?-p"${pawd}"?-D${db_name}?-N?-s?-e?"${select_sql}"?>connect_info
?
?#?循環(huán)遍歷
?while?read?line
?do
???#?獲取連接信息中的數(shù)據(jù)
???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?這里我們簡(jiǎn)單解釋下這段腳本,4~16行我們分別定義了7個(gè)變量,sh腳本定義變量的方式和python有點(diǎn)像,都不需要指定數(shù)據(jù)類(lèi)型;
mysql命令參數(shù)
18行我們執(zhí)行了一個(gè)mysql的命令,這行命令的作用是連接mysql并執(zhí)行sql語(yǔ)句,-e表示執(zhí)行并退出,后面直接跟sql語(yǔ)句,會(huì)直接打印sql,執(zhí)行完成后會(huì)打印sql結(jié)果:

我以前真不知道還有這種操作方式,不是這次統(tǒng)計(jì)數(shù)據(jù),應(yīng)該不會(huì)去了解。
-s表示以制表符分割顯示結(jié)果,不加這個(gè)參數(shù)的話,結(jié)果會(huì)包括|,也就是我們通??吹降慕Y(jié)果:

不加-s查詢(xún)結(jié)果如下:

加了-s顯示結(jié)果如下:

-N參數(shù)的作用是隱藏字段名稱(chēng),也就是title(加上這個(gè)參數(shù)可以保證我們查詢(xún)結(jié)果只有數(shù)據(jù)):

sh腳本要點(diǎn)
在sh腳本中,將運(yùn)行結(jié)果輸出到文件中有兩種方式,一種是>,另一種是>>,兩者的區(qū)別是,前者會(huì)覆寫(xiě)文件中的內(nèi)容,而后者是在文件中追加(如果文件中已經(jīng)存在內(nèi)容,則會(huì)在原有內(nèi)容后面追加新的內(nèi)容),這種操縱在sh中很普遍,比如:
#?將?ls?結(jié)果輸出到文件中
ls?/home/syske?>?file_list
#?將當(dāng)前時(shí)間輸出到文件中,每次追加
date?>>?date_list
<與>剛好相反,是將文件的內(nèi)容讀取出來(lái),比如:
?#?讀取?date_list
?cat?另外除了直接將命令結(jié)果輸出,我們還可以用變量接收運(yùn)行結(jié)果:
result=`mysql?-h?"${host}"?-P?"${port}"?-u"${user}"?-p"${pawd}"?-D${db_name}?-N?-s?-e?"${count_sql}"`
比如上面這行sh代碼就是用result接收mysql的運(yùn)行結(jié)果,需要注意的是命令必須通過(guò)( ` )進(jìn)行包裝,否則命令無(wú)法運(yùn)行。這種方式有個(gè)好處,就是可以對(duì)結(jié)果進(jìn)行處理,比如拼接變量:
?echo?"${config_id}?${result}"
運(yùn)行結(jié)果處理
拿到運(yùn)行結(jié)果之后,我們可以通過(guò)awk、sort等命令進(jìn)行處理,以拿到最終數(shù)據(jù)。比如我們的查詢(xún)結(jié)果如下:
Sun?Nov??7?16:59:54?CST?2021
Sun?Nov??7?16:59:57?CST?2021
Sun?Nov??7?16:59:58?CST?2021
如果是通過(guò)awk處理,則可以直接幫我們將數(shù)據(jù)分割成:sun、Nov、7、16:59:54、CST、2021這樣的格式,而且很簡(jiǎn)單:
?awk?'{print?$1,?$2,?$3,?$4,?$5,?$6}'?date_list
這里的$1表示分割的第一部分,也就是Sun,其他以此類(lèi)推;$0表示原始數(shù)據(jù)

排序的話,可以用sort命令進(jìn)行操作:
awk?'{print?$1,?$2,?$3,?$4,?$5,?$6}'?date_list?|?sort?-rk?4
排序結(jié)果如下:

其中-r表示降序排序,默認(rèn)是正序排序,-k表示按指定序列排序,4表示按第四列排序,也就是按時(shí)間排序。更多其他排序可以參考sort文檔。
最后再補(bǔ)充點(diǎn)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的初始值設(shè)置一個(gè)超大數(shù)即可)
awk?'BEGIN?{min?=?1999999}?{if?($1
擴(kuò)展知識(shí)
這里再分享win環(huán)境下的幾個(gè)常用命令:
關(guān)機(jī)操作:
#?休眠操作
shutdown?/h
#?重啟
shutdown?/r
#?定時(shí)關(guān)閉(兩小時(shí)后關(guān)機(jī),單位秒)
shutdown?/s?/t?3600
顯示指定文件夾下的所有內(nèi)容,包括文件和子文件夾:
dir?/b/s?./
顯示指定文件夾樹(shù)形結(jié)構(gòu):
tree?./

另外,我們前面說(shuō)了,win平臺(tái)也支持>和>>,這樣我們就可以把上面命令的結(jié)果輸出到文件中:
dir?/b/s?./?>?file_list.log
tree?./?>>?struts.log
批量修改文件后綴(文件名)
#?修改文件擴(kuò)展名
ren?*.gif?*.jpg
#?或者(ren和rename等同)
rename?*.gif?*.jpg
#?修改文件名
ren?*.gif?*-syske.gif批量刪除文件
#?我經(jīng)常通過(guò)這樣的方式刪除重復(fù)文件
del?*(1).jpg
結(jié)語(yǔ)
shell腳本統(tǒng)計(jì)數(shù)據(jù)的內(nèi)容我們就分享這么多,核心知識(shí)點(diǎn)包括shell的基本語(yǔ)法、linux的常用命令等,總體的內(nèi)容難點(diǎn)并不大,如果實(shí)際工作中遇到了類(lèi)似的需求,各位小伙伴可以參考。
最后,還想多說(shuō)兩句。在我的理解中,我覺(jué)得一切工具都可以變成生產(chǎn)力工具,最關(guān)鍵的還是要學(xué)會(huì)活學(xué)活用,養(yǎng)成一個(gè)善于動(dòng)腦的小可愛(ài),這樣才能避免低效重復(fù)工作,有時(shí)候同樣的工具,關(guān)鍵在于你如何用,你是否能夠發(fā)現(xiàn)它的價(jià)值點(diǎn),現(xiàn)實(shí)中的栗子有很多,比如回形針的一百種用法。
當(dāng)然,實(shí)際工作中也會(huì)遇到很多類(lèi)似的問(wèn)題,比如你現(xiàn)在需要修改一批線上數(shù)據(jù)(400多條),數(shù)據(jù)的條件和更新內(nèi)容各不相同,你能想到哪些處理方式?通過(guò)編輯器批量修改?還是手工一條一條修改?還是借助其他工具,python、excel?上周五我就完成了這樣的工作,最終通過(guò)excel生成update sql,通過(guò)文本編輯器批量插入和替換拼接緩存key,最后完成相關(guān)數(shù)據(jù)修改。我說(shuō)這個(gè)例子是希望各位小伙伴在學(xué)習(xí)和實(shí)踐的時(shí)候,要學(xué)會(huì)發(fā)散思維,不要被當(dāng)前的語(yǔ)言、環(huán)境、方法所局限,要學(xué)會(huì)解決問(wèn)題,學(xué)會(huì)知識(shí)的橫向應(yīng)用,橫向思考。好了,今天廢話有點(diǎn)多,各位小伙伴,晚安吧!
