手機游戲網(wǎng)站建設(shè)電商怎么推廣自己的產(chǎn)品
【BASH】回顧與知識點梳理 十七
- 十七. 什么是 Shell scripts
- 17.1 干嘛學(xué)習(xí) shell scripts
- 自動化管理的重要依據(jù)
- 追蹤與管理系統(tǒng)的重要工作
- 簡單入侵檢測功能
- 連續(xù)指令單一化
- 簡易的數(shù)據(jù)處理
- 跨平臺支持與學(xué)習(xí)歷程較短
- 17.2 第一支 script 的撰寫與執(zhí)行
- 撰寫第一支 script
- 17.3 撰寫 shell script 的良好習(xí)慣建立
- 17.4 簡單范例
- 對談式腳本:變量內(nèi)容由用戶決定
- 隨日期變化:利用 date 進行文件的建立
- 數(shù)值運算:簡單的加減乘除
- 數(shù)值運算:透過 bc 計算 pi
- 17.5 script 的執(zhí)行方式差異 (source, sh script, ./script)
- 利用直接執(zhí)行的方式來執(zhí)行 script
- 利用 source 來執(zhí)行腳本:在父程序中執(zhí)行
該系列目錄 --> 【BASH】回顧與知識點梳理(目錄)
如果你真的很想要走信息這條路,并且想要管理好屬于你的主機,那么,別說鳥哥不告訴你, 可以自動管理系統(tǒng)的好工具: Shell scripts!這家伙真的是得要好好學(xué)習(xí)學(xué)習(xí)的! 基本上, shell script 有點像是早期的批處理文件,亦即是將一些指令匯整起來一次執(zhí)行,但是 Shell script 擁有更強大的功能,那就是他可以進行類似程序 (program) 的撰寫,并且不需要經(jīng)過編譯 (compile) 就能夠執(zhí)行, 真的很方便。加上我們可透過 shell script 來簡化我們?nèi)粘5墓ぷ鞴芾?#xff0c; 而且,整個Linux 環(huán)境中,一些服務(wù) (services) 的啟動都是透過 shell script 的, 如果你對于 script 不了解,嘿嘿!發(fā)生問題時,可真是會求助無門喔!所以,好好的學(xué)一學(xué)他吧!
十七. 什么是 Shell scripts
什么是 shell script (程序化腳本) 呢?就字面上的意義,我們將他分為兩部份。 在『 shell 』部分,那是一個文字接口底下讓我們與系統(tǒng)溝通的一個工具接口。那么『 script 』是啥? 字面上的意義, script 是『腳本、劇本』的意思。整句話是說, shell script 是針對 shell 所寫的『劇本!』
什么東西啊?其實, shell script 是利用 shell 的功能所寫的一個『程序 (program)』,這個程序是使用純文本文件,將一些 shell 的語法與指令(含外部指令)寫在里面, 搭配正規(guī)表示法、管線命令與數(shù)據(jù)流重導(dǎo)向等功能,以達到我們所想要的處理目的。
所以,簡單的說, shell script 就像是早期 DOS 年代的批處理文件 (.bat) ,最簡單的功能就是將許多指令匯整寫在一起, 讓使用者很輕易的就能夠 one touch 的方法去處理復(fù)雜的動作 (執(zhí)行一個文件 “shell script” ,就能夠一次執(zhí)行多個指令)。 而且 shell script 更提供數(shù)組、循環(huán)、條件與邏輯判斷等重要功能,讓用戶也可以直接以 shell 來撰寫程序,而不必使用類似 C 程序語言等傳統(tǒng)程序撰寫的語法呢!
這么說你可以了解了嗎?是的! shell script 可以簡單的被看成是批處理文件, 也可以被說成是一個程序語言,且這個程序語言由于都是利用 shell 與相關(guān)工具指令, 所以不需要編譯即可執(zhí)行,且擁有不錯的除錯 (debug) 工具,所以,他可以幫助系統(tǒng)管理員快速的管理好主機。
17.1 干嘛學(xué)習(xí) shell scripts
這是個好問題:『我又干嘛一定要學(xué) shell script ?我又不是信息人,沒有寫程序的概念, 那我干嘛還要學(xué) shell script 呢?不要學(xué)可不可以啊?』呵呵~如果 Linux 對你而言, 你只是想要『會用』而已,那么,不需要學(xué) shell script 也還無所謂,這部分先給他跳過去, 等到有空的時候,再來好好的瞧一瞧。但是,如果你是真的想要玩清楚 Linux 的來龍去脈, 那么 shell script 就不可不知,為什么呢?因為:
自動化管理的重要依據(jù)
不用鳥哥說你也知道,管理一部主機真不是件簡單的事情,每天要進行的任務(wù)就有:查詢登錄檔、追蹤流量、監(jiān)控用戶使用主機狀態(tài)、主機各項硬設(shè)備狀態(tài)、 主機軟件更新查詢、更不要說得應(yīng)付其他使用者的突然要求了。而這些工作的進行可以分為: (1)自行手動處理,或是 (2)寫個簡單的程序來幫你每日『自動處理分析』這兩種方式,你覺得哪種方式比較好? 當然是讓系統(tǒng)自動工作比較好,對吧!呵呵~這就得要良好的 shell script 來幫忙的啦!
追蹤與管理系統(tǒng)的重要工作
雖然我們還沒有提到服務(wù)啟動的方法,不過,這里可以先提一下,我們 CentOS 6.x 以前的版本中,系統(tǒng)的服務(wù) (services) 啟動的接口是在 /etc/init.d/ 這個目錄下,目錄下的所有文件都是 scripts ;另外,包括開機 (booting) 過程也都是利用 shell script 來幫忙搜尋系統(tǒng)的相關(guān)設(shè)定數(shù)據(jù), 然后再代入各個服務(wù)的設(shè)定參數(shù)啊!舉例來說,如果我們想要重新啟動系統(tǒng)注冊表檔, 可以使用:『/etc/init.d/rsyslogd restart』,那個 rsyslogd 文件就是 script 啦!
另外,鳥哥曾經(jīng)在某一代的 Fedora 上面發(fā)現(xiàn),啟動 MySQL 這個數(shù)據(jù)庫服務(wù)時,確實是可以啟動的, 但是屏幕上卻老是出現(xiàn)『failure』!后來才發(fā)現(xiàn),原來是啟動 MySQL 那個 script 會主動的以『空的密碼』去嘗試登入 MySQL ,但為了安全性鳥哥修改過 MySQL 的密碼啰~當然就登入失敗~ 后來改了改 script ,就略去這個問題啦!如此說來, script 確實是需要學(xué)習(xí)的啊!
時至今日,雖然 /etc/init.d/* 這個腳本啟動的方式 (systemV) 已經(jīng)被新一代的 systemd 所取代(從 CentOS 7 開始), 但是很多的個別服務(wù)在管理他們的服務(wù)啟動方面,還是使用 shell script 的機制喔!所以,最好還是能夠熟悉啦!
簡單入侵檢測功能
當我們的系統(tǒng)有異狀時,大多會將這些異狀記錄在系統(tǒng)記錄器,也就是我們常提到的『系統(tǒng)注冊表檔』, 那么我們可以在固定的幾分鐘內(nèi)主動的去分析系統(tǒng)注冊表檔,若察覺有問題,就立刻通報管理員, 或者是立刻加強防火墻的設(shè)定規(guī)則,如此一來,你的主機可就能夠達到『自我保護』的聰明學(xué)習(xí)功能啦~ 舉例來說,我們可以通過 shell script 去分析『當該封包嘗試幾次還是聯(lián)機失敗之后,就予以抵擋住該 IP』之類的舉動,例如鳥哥寫過一個關(guān)于抵擋砍站軟件的 shell script ,就是用這個想法去達成的呢!
連續(xù)指令單一化
其實,對于新手而言, script 最簡單的功能就是:『匯整一些在 command line 下達的連續(xù)指令,將他寫入 scripts 當中,而由直接執(zhí)行 scripts 來啟動一連串的 command line 指令輸入!』例如:防火墻連續(xù)規(guī)則 (iptables),開機加載程序的項目 (就是在 /etc/rc.d/rc.local 里頭的數(shù)據(jù)) ,等等都是相似的功能啦! 其實,說穿了,如果不考慮 program 的部分,那么 scripts 也可以想成『僅是幫我們把一大串的指令匯整在一個文件里面, 而直接執(zhí)行該文件就可以執(zhí)行那一串又臭又長的指令段!』就是這么簡單啦!
簡易的數(shù)據(jù)處理
由前一章正規(guī)表示法的 awk 程序說明中, 你可以發(fā)現(xiàn), awk 可以用來處理簡單的數(shù)據(jù)數(shù)據(jù)呢!例如薪資單的處理啊等等的。 shell script 的功能更強大,例如鳥哥曾經(jīng)用 shell script 直接處理數(shù)據(jù)數(shù)據(jù)的比對啊, 文字數(shù)據(jù)的處理啊等等的,撰寫方便,速度又快(因為在 Linux 效能較佳),真的是很不錯用的啦!
舉例來說,鳥哥每學(xué)期都得要以學(xué)生的學(xué)號來建立他們能夠操作 Linux 的系統(tǒng)賬號,然后每個賬號還得要能夠有磁盤容量的限制 (quota) 以及相關(guān)的設(shè)定等等, 那因為學(xué)校的校務(wù)系統(tǒng)提供的數(shù)據(jù)都是一整串學(xué)生信息,并沒有單純的學(xué)號字段,所以鳥哥就得要透過前幾章的方法搭配 shell script 來自動處理相關(guān)設(shè)定流程, 這樣才不會每學(xué)期都頭疼一次啊!
跨平臺支持與學(xué)習(xí)歷程較短
幾乎所有的 Unix Like 上面都可以跑 shell script ,連 MS Windows 系列也有相關(guān)的 script 仿真器可以用, 此外, shell script 的語法是相當親和的,看都看的懂得文字 (雖然是英文),而不是機器碼, 很容易學(xué)習(xí)~這些都是你可以加以考慮的學(xué)習(xí)點啊!
上面這些都是你考慮學(xué)習(xí) shell script 的特點~此外, shell script 還可以簡單的以 vim 來直接編寫,實在是很方便的好東西!所以,還是建議你學(xué)習(xí)一下啦。
不過,雖然 shell script 號稱是程序 (program) ,但實際上, shell script 處理數(shù)據(jù)的速度上是不太夠的。因為 shell script 用的是外部的指令與 bash shell 的一些默認工具,所以,他常常會去呼叫外部的函式庫,因此,指令周期上面當然比不上傳統(tǒng)的程序語言。 所以啰, shell script 用在系統(tǒng)管理上面是很好的一項工具,但是用在處理大量數(shù)值運算上, 就不夠好了,因為 Shell scripts 的速度較慢,且使用的 CPU 資源較多,造成主機資源的分配不良。還好, 我們通常利用 shell script 來處理服務(wù)器的偵測,倒是沒有進行大量運算的需求啊!所以不必擔心的啦!
17.2 第一支 script 的撰寫與執(zhí)行
如同前面講到的,shell script 其實就是純文本檔,我們可以編輯這個文件,然后讓這個文件來幫我們一次執(zhí)行多個指令, 或者是利用一些運算與邏輯判斷來幫我們達成某些功能。所以啦,要編輯這個文件的內(nèi)容時,當然就需要具備有 bash 指令下達的相關(guān)認識。 在 shell script 的撰寫中還需要用到底下的注意事項:
- 指令的執(zhí)行是從上而下、從左而右的分析與執(zhí)行;
- 指令的下達就如同前面提到的: 指令、選項與參數(shù)間的多個空白都會被忽略掉;
- 空白行也將被忽略掉,并且 [tab] 按鍵所推開的空白同樣視為空格鍵;
- 如果讀取到一個 Enter 符號 (CR) ,就嘗試開始執(zhí)行該行 (或該串) 命令;
- 至于如果一行的內(nèi)容太多,則可以使用『 [Enter] 』來延伸至下一行;
- 『 # 』可做為批注!任何加在 # 后面的資料將全部被視為批注文字而被忽略!
如此一來,我們在 script 內(nèi)所撰寫的程序,就會被一行一行的執(zhí)行?,F(xiàn)在我們假設(shè)你寫的這個程序文件名是 /home/dmtsai/shell.sh 好了,那如何執(zhí)行這個文件?很簡單,可以有底下幾個方法:
- 直接指令下達: shell.sh 文件必須要具備可讀與可執(zhí)行 (rx) 的權(quán)限,然后:
- 絕對路徑:使用 /home/dmtsai/shell.sh 來下達指令;
- 相對路徑:假設(shè)工作目錄在 /home/dmtsai/ ,則使用 ./shell.sh 來執(zhí)行
- 變量『PATH』功能:將 shell.sh 放在 PATH 指定的目錄內(nèi),例如: ~/bin/
- 以 bash 程序來執(zhí)行:透過『 bash shell.sh 』或『 sh shell.sh 』來執(zhí)行
反正重點就是要讓那個 shell.sh 內(nèi)的指令可以被執(zhí)行的意思啦!咦!那我為何需要使用『./shell.sh 』來下達指令?忘記了嗎?同時,由于CentOS 默認用戶家目錄下的 ~/bin 目錄會被設(shè)定到 ${PATH} 內(nèi),所以你也可以將 shell.sh 建立在/home/dmtsai/bin/ 底下 ( ~/bin 目錄需要自行設(shè)定) 。此時,若 shell.sh 在 ~/bin 內(nèi)且具有 rx 的權(quán)限,那就直接輸入 shell.sh 即可執(zhí)行該腳本程序!
那為何『 sh shell.sh 』也可以執(zhí)行呢?這是因為 /bin/sh 其實就是 /bin/bash (連結(jié)檔),使用 sh shell.sh 亦即告訴系統(tǒng),我想要直接以 bash 的功能來執(zhí)行 shell.sh 這個文件內(nèi)的相關(guān)指令的意思,所以此時你的 shell.sh 只要有 r 的權(quán)限即可被執(zhí)行喔!而我們也可以利用 sh 的參數(shù),如 -n 及 -x 來檢查與追蹤 shell.sh 的語法是否正確呢! ^_^
撰寫第一支 script
在武俠世界中,不論是那個門派,要學(xué)武功要從掃地與蹲馬步做起,那么要學(xué)程序呢?呵呵,肯定是由『秀出 Hello World!』 這個字眼開始的!OK!那么鳥哥就先寫一支 script 給大家瞧一瞧:
[dmtsai@study ~]$ mkdir bin; cd bin
[dmtsai@study bin]$ vim hello.sh
#!/bin/bash
# Program:
# This program shows "Hello World!" in your screen.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "Hello World! \a \n"
exit 0
在本章當中,請將所有撰寫的 script 放置到你家目錄的 ~/bin 這個目錄內(nèi),未來比較好管理啦!上面的寫法當中,鳥哥主要將整個程序的撰寫分成數(shù)段,大致是這樣:
-
第一行
#!/bin/bash
在宣告這個 script 使用的 shell 名稱:
因為我們使用的是 bash ,所以,必須要以『#!/bin/bash
』來宣告這個文件內(nèi)的語法使用 bash 的語法!那么當這個程序被執(zhí)行時,他就能夠加載 bash 的相關(guān)環(huán)境配置文件 (一般來說就是 non-login shell 的~/.bashrc), 并且執(zhí)行 bash 來使我們底下的指令能夠執(zhí)行!這很重要的!(在很多狀況中,如果沒有設(shè)定好這一行, 那么該程序很可能會無法執(zhí)行,因為系統(tǒng)可能無法判斷該程序需要使用什么 shell 來執(zhí)行啊!) -
程序內(nèi)容的說明:
整個 script 當中,除了第一行的『 #! 』是用來宣告 shell 的之外,其他的 # 都是『批注』用途! 所以上面的程序當中,第二行以下就是用來說明整個程序的基本數(shù)據(jù)。一般來說, 建議你一定要養(yǎng)成說明該script 的:1. 內(nèi)容與功能; 2. 版本信息; 3. 作者與聯(lián)絡(luò)方式; 4. 建檔日期;5. 歷史紀錄 等等。這將有助于未來程序的改寫與 debug 呢! -
主要環(huán)境變量的宣告:
建議務(wù)必要將一些重要的環(huán)境變量設(shè)定好,鳥哥個人認為, PATH 與 LANG (如果有使用到輸出相關(guān)的信息時) 是當中最重要的! 如此一來,則可讓我們這支程序在進行時,可以直接下達一些外部指令,而不必寫絕對路徑呢!比較方便啦! -
主要程序部分
就將主要的程序?qū)懞眉纯?#xff01;在這個例子當中,就是 echo 那一行啦! -
執(zhí)行成果告知 (定義回傳值)
是否記得我們在第十章里面要討論一個指令的執(zhí)行成功與否,可以使用$?
這個變量來觀察~ 那么我們也可以利用 exit 這個指令來讓程序中斷,并且回傳一個數(shù)值給系統(tǒng)。 在我們這個例子當中,鳥哥使用 exit 0 ,這代表離開 script 并且回傳一個 0 給系統(tǒng), 所以我執(zhí)行完這個 script 后,若接著下達echo $?
則可得到0 的值喔! 更聰明的讀者應(yīng)該也知道了,呵呵!利用這個 exit n (n 是數(shù)字) 的功能,我們還可以自定義錯誤訊息, 讓這支程序變得更加的 smart 呢!
接下來透過剛剛上頭介紹的執(zhí)行方法來執(zhí)行看看結(jié)果吧!
[dmtsai@study bin]$ sh hello.sh
Hello World !
你會看到屏幕是這樣,而且應(yīng)該還會聽到『咚』的一聲,為什么呢?還記得前一章提到的 printf 吧?用 echo 接著那些特殊的按鍵也可以發(fā)生同樣的事情~ 不過, echo 必須要加上 -e 的選項才行!呵呵!
另外,你也可以利用:『chmod a+x hello.sh; ./hello.sh
』來執(zhí)行這個 script 的呢!
17.3 撰寫 shell script 的良好習(xí)慣建立
一個良好習(xí)慣的養(yǎng)成是很重要的~大家在剛開始撰寫程序的時候,最容易忽略這部分, 認為程序?qū)懗鰜砭秃昧?#xff0c;其他的不重要。其實,如果程序的說明能夠更清楚,那么對你自己是有很大的幫助的。
舉例來說,鳥哥自己為了自己的需求,曾經(jīng)撰寫了不少的 script 來幫我進行主機 IP 的偵測啊、 登錄檔分析與管理啊、自動上傳下載重要配置文件啊等等的,不過,早期就是因為太懶了, 管理的主機又太多了,常常同一個程序在不同的主機上面進行更改,到最后,到底哪一支才是最新的都記不起來, 而且,重點是,我到底是改了哪里?為什么做那樣的修改?都忘的一乾二凈~真要命~
所以,后來鳥哥在寫程序的時候,通常會比較仔細的將程序的設(shè)計過程給他記錄下來,而且還會記錄一些歷史紀錄, 如此一來,好多了~至少很容易知道我修改了哪些數(shù)據(jù),以及程序修改的理念與邏輯概念等等, 在維護上面是輕松很多很多的喔!
另外,在一些環(huán)境的設(shè)定上面,畢竟每個人的環(huán)境都不相同,為了取得較佳的執(zhí)行環(huán)境, 我都會自行先定義好一些一定會被用到的環(huán)境變量,例如 PATH 這個玩意兒! 這樣比較好啦~所以說,建議你一定要養(yǎng)成良好的 script 撰寫習(xí)慣,在每個 script 的文件頭處記錄好:
- script 的功能;
- script 的版本信息;
- script 的作者與聯(lián)絡(luò)方式;
- script 的版權(quán)宣告方式;
- script 的 History (歷史紀錄);
- script 內(nèi)較特殊的指令,使用『絕對路徑』的方式來下達;
- script 運作時需要的環(huán)境變量預(yù)先宣告與設(shè)定。
除了記錄這些信息之外,在較為特殊的程序代碼部分,個人建議務(wù)必要加上批注說明,可以幫助你非常非常多! 此外,程序代碼的撰寫最好使用巢狀方式,在包覆的內(nèi)部程序代碼最好能以 [tab] 按鍵的空格向后推
,這樣你的程序代碼會顯的非常的漂亮與有條理!在查閱與 debug 上較為輕松愉快喔!
另外,使用撰寫 script 的工具最好使用 vim 而不是 vi
,因為 vim 會有額外的語法檢驗機制,能夠在第一階段撰寫時就發(fā)現(xiàn)語法方面的問題喔!
17.4 簡單范例
底下的范例在很多的腳本程序中都會用到,而底下的范例又都很簡單!值得參考看看喔!
對談式腳本:變量內(nèi)容由用戶決定
很多時候我們需要使用者輸入一些內(nèi)容,好讓程序可以順利運作。 簡單的來說,大家應(yīng)該都有安裝過軟件的經(jīng)驗,安裝的時候,他不是會問你『要安裝到那個目錄去』嗎? 那個讓用戶輸入數(shù)據(jù)的動作,就是讓用戶輸入變量內(nèi)容啦。
你應(yīng)該還記得在十章 bash 的時候,我們有學(xué)到一個 read 指令吧?現(xiàn)在,請你以 read 指令的用途,撰寫一個 script ,他可以讓使用者輸入:1. first name 與 2. last name,最后并且在屏幕上顯示:『Your full name is: 』的內(nèi)容:
[dmtsai@study bin]$ vim showname.sh
#!/bin/bash
# Program:
# User inputs his first name and last name. Program shows his full name.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "Please input your first name: " firstname # 提示使用者輸入
將上面這個 showname.sh 執(zhí)行一下,你就能夠發(fā)現(xiàn)用戶自己輸入的變量可以讓程序所取用,并且將他顯示到屏幕上! 接下來,如果想要制作一個每次執(zhí)行都會依據(jù)不同的日期而變化結(jié)果的腳本呢?
隨日期變化:利用 date 進行文件的建立
想象一個狀況,假設(shè)我的服務(wù)器內(nèi)有數(shù)據(jù)庫,數(shù)據(jù)庫每天的數(shù)據(jù)都不太一樣,因此當我備份時,希望將每天的資料都備份成不同的檔名, 這樣才能夠讓舊的數(shù)據(jù)也能夠保存下來不被覆蓋。哇!不同檔名呢!這真困擾啊?難道要我每天去修改 script ?
不需要啊!考慮每天的『日期』并不相同,所以我可以將檔名取成類似: backup.2015-07-16.data ,不就可以每天一個不同檔名了嗎?呵呵!確實如此。那個 2015-07-16 怎么來的?那就是重點啦!接下來出個相關(guān)的例子: 假設(shè)我想要建立三個空的文件 (透過 touch) ,檔名最開頭由使用者輸入決定,假設(shè)使用者輸入 filename 好了,那今天的日期是 2015/07/16 , 我想要以前天、昨天、今天的日期來建立這些文件,亦即 filename_20150714, filename_20150715, filename_20150716 ,該如何是好?
[dmtsai@study bin]$ vim create_3_filename.sh
#!/bin/bash
# Program:
# Program creates three files, which named by user's input and date command.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# 1. 讓使用者輸入文件名,并取得 fileuser 這個變量;
echo -e "I will use 'touch' command to create 3 files." # 純粹顯示信息
read -p "Please input your filename: " fileuser # 提示使用者輸入
# 2. 為了避免使用者隨意按 Enter ,利用變量功能分析檔名是否有設(shè)定?
filename=${fileuser:-"filename"} # 開始判斷有否配置文件名
# 3. 開始利用 date 指令來取得所需要的檔名了;
date1=$(date --date='2 days ago' +%Y%m%d) # 前兩天的日期
date2=$(date --date='1 days ago' +%Y%m%d) # 前一天的日期
date3=$(date +%Y%m%d) # 今天的日期
file1=${filename}${date1} # 底下三行在配置文件名
file2=${filename}${date2}
file3=${filename}${date3}
# 4. 將檔名建立吧!
touch "${file1}" # 底下三行在建立文件
touch "${file2}"
touch "${file3}"
上面的范例鳥哥使用了很多在第十章介紹過的概念: 包括小指令『 $(command) 』的取得訊息、變量的設(shè)定功能、變量的累加以及利用 touch 指令輔助! 如果你開始執(zhí)行這個 create_3_filename.sh 之后,你可以進行兩次執(zhí)行:一次直接按 [Enter] 來查閱檔名是啥? 一次可以輸入一些字符,這樣可以判斷你的腳本是否設(shè)計正確喔!
數(shù)值運算:簡單的加減乘除
各位看官應(yīng)該還記得,我們可以使用 declare 來定義變量的類型吧? 當變量定義成為整數(shù)后才能夠進行加減運算啊!此外,我們也可以利用『 $((計算式))
』來進行數(shù)值運算的。 可惜的是, bash shell 里頭預(yù)設(shè)僅支持到整數(shù)的數(shù)據(jù)而已。OK!那我們來玩玩看,如果我們要用戶輸入兩個變量, 然后將兩個變量的內(nèi)容相乘,最后輸出相乘的結(jié)果,那可以怎么做?
#!/bin/bash
# Program:
# User inputs 2 integer numbers; program will cross these two numbers.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "You SHOULD input 2 numbers, I will multiplying them! \n"
read -p "first number: " firstnu
read -p "second number: " secnu
total=$((${firstnu}*${secnu}))
echo -e "\nThe result of ${firstnu} x ${secnu} is ==> ${total}"
在數(shù)值的運算上,我們可以使用『 declare -i total=${firstnu}*${secnu}
』 也可以使用上面的方式來進行!基本上,鳥哥比較建議使用這樣的方式來進行運算:
var=$((運算內(nèi)容))
不但容易記憶,而且也比較方便的多,因為兩個小括號內(nèi)可以加上空格符喔! 未來你可以使用這種方式來計算的呀!至于數(shù)值運算上的處理,則有:『+, -, *, /, %
』等等。 那個 % 是取余數(shù)啦~舉例來說, 13 對 3 取余數(shù),結(jié)果是 13=4*3+1,所以余數(shù)是 1 啊!就是:
[dmtsai@study bin]$ echo $(( 13 % 3 ))
1
這樣了解了吧?另外,如果你想要計算含有小數(shù)點的數(shù)據(jù)時,其實可以透過 bc 這個指令的協(xié)助喔!例如可以這樣做:
[dmtsai@study bin]$ echo "123.123*55.9" | bc
6882.575
了解了 bc 的妙用之后,來讓我們測試一下如何計算 pi 這個東西呢?
數(shù)值運算:透過 bc 計算 pi
其實計算 pi 時,小數(shù)點以下位數(shù)可以無限制的延伸下去!而 bc 有提供一個運算 pi 的函式,只是想要使用該函式必須要使用 bc -l
來呼叫才行。 也因為這個小數(shù)點以下位數(shù)可以無線延伸運算的特性存在,所以我們可以透過底下這只小腳本來讓使用者輸入一個『小數(shù)點為數(shù)值
』, 以讓 pi 能夠更準確!
#!/bin/bash
# Program:
# User input a scale number to calculate pi number.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "This program will calculate pi value. \n"
echo -e "You should input a float number to calculate pi value.\n"
read -p "The scale number (10~10000) ? " checking
num=${checking:-"10"} # 開始判斷有否有輸入數(shù)值
echo -e "Starting calcuate pi value. Be patient."
time echo "scale=${num}; 4*a(1)" | bc -lq
上述數(shù)據(jù)中,那個 4*a(1)
是 bc 主動提供的一個計算 pi 的函數(shù),至于 scale 就是要 bc 計算幾個小數(shù)點下位數(shù)的意思。當 scale 的數(shù)值越大, 代表 pi 要被計算的越精確,當然用掉的時間就會越多!因此,你可以嘗試輸入不同的數(shù)值看看!不過,最好是不要超過 5000 啦!因為會算很久! 如果你要讓你的 CPU 隨時保持在高負載,這個程序算下去你就會知道有多操 CPU 啰!
鳥哥的實驗室中,為了要確認虛擬機的效率問題,所以很多時候需要保持虛擬機在忙碌的狀態(tài)~鳥哥的學(xué)生就是丟這只程序進去系統(tǒng)跑! 但是將 scale 調(diào)高一些,那計算就得要花比較多時間~用以達到我們需要 CPU 忙碌的狀態(tài)喔!
17.5 script 的執(zhí)行方式差異 (source, sh script, ./script)
不同的 script 執(zhí)行方式會造成不一樣的結(jié)果喔!尤其影響 bash 的環(huán)境很大呢!腳本的執(zhí)行方式除了前面小節(jié)談到的方式之外,還可以利用 source 或小數(shù)點 (.) 來執(zhí)行喔!那么這種執(zhí)行方式有何不同呢?當然是不同的啦!讓我們來說說!
利用直接執(zhí)行的方式來執(zhí)行 script
當使用前一小節(jié)提到的直接指令下達 (不論是絕對路徑/相對路徑還是 ${PATH} 內(nèi)),或者是利用bash (或 sh) 來下達腳本時, 該 script 都會使用一個新的 bash 環(huán)境來執(zhí)行腳本內(nèi)的指令!也就是說,使用這種執(zhí)行方式時, 其實 script 是在子程序的 bash 內(nèi)執(zhí)行的!我們在前面談到 export 的功能時,曾經(jīng)就父程序/子程序談過一些概念性的問題, 重點在于:『當子程序完成后,在子程序內(nèi)的各項變量或動作將會結(jié)束而不會傳回到父程序中
』! 這是什么意思呢?
我們舉剛剛提到過的 showname.sh 這個腳本來說明好了,這個腳本可以讓用戶自行設(shè)定兩個變量,分別是 firstname 與 lastname,想一想,如果你直接執(zhí)行該指令時,該指令幫你設(shè)定的 firstname 會不會生效?看一下底下的執(zhí)行結(jié)果:
[dmtsai@study bin]$ echo ${firstname} ${lastname}<==確認了,這兩個變量并不存在喔!
[dmtsai@study bin]$ sh showname.sh
Please input your first name: VBird <==這個名字是鳥哥自己輸入的
Please input your last name: Tsai
Your full name is: VBird Tsai <==看吧!在 script 運作中,這兩個變數(shù)有生效
[dmtsai@study bin]$ echo ${firstname} ${lastname}<==事實上,這兩個變量在父程序的 bash 中還是不存在的!
上面的結(jié)果你應(yīng)該會覺得很奇怪,怎么我已經(jīng)利用 showname.sh 設(shè)定好的變量竟然在 bash 環(huán)境底下無效!怎么回事呢? 如果將程序相關(guān)性繪制成圖的話,我們以下圖來說明。當你使用直接執(zhí)行的方法來處理時,系統(tǒng)會給予一支新的 bash 讓我們來執(zhí)行 showname.sh 里面的指令,因此你的firstname, lastname 等變量其實是在下圖中的子程序 bash 內(nèi)執(zhí)行的。 當 showname.sh 執(zhí)行完畢后,子程序 bash 內(nèi)的所有數(shù)據(jù)便被移除,因此上表的練習(xí)中,在父程序底下 echo ${firstname} 時, 就看不到任何東西了!這樣可以理解嗎?
利用 source 來執(zhí)行腳本:在父程序中執(zhí)行
如果你使用 source 來執(zhí)行指令那就不一樣了!同樣的腳本我們來執(zhí)行看看:
[dmtsai@study bin]$ source showname.sh
Please input your first name: VBird
Please input your last name: Tsai
Your full name is: VBird Tsai
[dmtsai@study bin]$ echo ${firstname} ${lastname}
VBird Tsai <==嘿嘿!有數(shù)據(jù)產(chǎn)生喔!
竟然生效了!沒錯啊!因為 source 對 script 的執(zhí)行方式可以使用底下的圖示來說明! showname.sh 會在父程序中執(zhí)行的,因此各項動作都會在原本的 bash 內(nèi)生效!這也是為啥你不注銷系統(tǒng)而要讓某些寫入 ~/.bashrc 的設(shè)定生效時,需要使用『 source ~/.bashrc 』而不能使用『 bash ~/.bashrc 』是一樣的啊!
該系列目錄 --> 【BASH】回顧與知識點梳理(目錄)