1. 程式人生 > 其它 >第17章 大資料定製篇-Shell程式設計

第17章 大資料定製篇-Shell程式設計

17.1 為什麼要學習Shell程式設計

1)Linux運維工程師在進行伺服器叢集管理時,需要編寫Shell程式來進行伺服器管理。
2)對於JavaEE和Python程式設計師來說,工作的需要,你的老大會要求你編寫一些Shell指令碼進行程式或者是伺服器的維護,比如編寫一個定時備份資料庫的指令碼。
3)對於大資料程式設計師來說,需要編寫Shell程式來管理叢集

 


17.2 Shell是什麼

Shell是一個命令列直譯器,它為使用者提供了一個向Linux核心傳送請求以便執行程式的介面系統級程式,使用者可以用Shell來啟動、掛起、停止甚至是編寫一些程式。看一個示意圖

 

 

 

 

 

17.3 Shell指令碼的執行方式

17.3.1指令碼格式要求

1)指令碼以 #!/bin/bash 開頭
2)指令碼需要有可執行許可權


17.3.2編寫第一個Shell指令碼

需求說明: 建立一個Shell 指令碼,輸出hello world!
vim hello.sh
#!/bin/bash
echo "hello,world~"

 

17.3.3指令碼的常用執行方式

方式1(輸入指令碼的絕對路徑或相對路徑)
說明:首先要賦予 helloworld.sh 指令碼的+x許可權,再執行指令碼
比如 ./hello.sh 或者使用絕對路徑 /root/shcode/hello.sh
方式2(sh+指令碼)
說明:不用賦予指令碼+x許可權,直接執行即可。
比如sh hello.sh, 也可以使用絕對路徑

 


17.4 Shell的變數

17.4.1 Shell變數介紹

1) Linux Shell中的變數分為,系統變數和使用者自定義變數。
2) 系統變數: $HOME、 $PWD、$SHELL、$USER 等等,比如:echo $HOME 等等..
3) 顯示當前 shell 中所有變數: set


17.4.2 shell 變數的定義

 

基本語法

1) 定義變數:變數名=值
2) 撤銷變數: unset 變數
3) 宣告靜態變數: readonly變數,注意:不能unset

 

快速入門

1) 案例1:定義變數A
2) 案例2:撤銷變數A
3) 案例3:宣告靜態的變數B=2,不能unset

4)案例4:可把變數提升為全域性環境變數,可供其他shell程式使用[該案例後面講]

 

#!/bin/bash
#案例1:定義變數A
A=100
#輸出變數需要加上$
echoA=$A
echo "A=$A"
#案例2:撤銷變數A
unset A
echo "A=$A"
#案例3:宣告靜態的變數 B=2,不能unset
readonly B=2
echo "B=$B"
#unset B
#將指令返回的結果賦給變數

:<<!
C=`date`
D=$(date)
echo "C=$C"
echo "D=$D"
!
#使用環境變數TOMCAT_HOME
echo "tomcat_home=$TOMCAT_HOME"

 

 

17.4.3 shell 變數的定義

定義變數的規則
1) 變數名稱可以由字母、數字和下劃線組成,但是不能以數字開頭。5A=200(x)
2) 等號兩側不能有空格
3) 變數名稱一般習慣為大寫,這是一個規範, 我們遵守即可

將命令的返回值賦給變數
1) A=`date`反引號,執行裡面的命令,並把結果返回給變數A
2) A=$(date) 等價於反引號

 

 

17.5設定環境變數

17.5.1基本語法

1) export 變數名=變數值  (功能描述:將shell變數輸出為環境變數/全域性變數)
2) source 配置檔案           (功能描述:讓修改後的配置資訊立即生效)
3) echo $變數名                 (功能描述:查詢環境變數的值)
4) 示意

 

 

 

 

17.5.2 快速入門

1)在 /etc/profile 檔案中定義 TOMCAT_HOME 環境變數

2)檢視環境變數 TOMCAT_HOME的值
3)在另外一個 shell 程式中使用 TOMCAT_HOME
注意:在輸出 TOMCAT_HOME 環境變數前,需要讓其生效.
source /etc/profile

 

 

 

shell 指令碼的多行註釋

:<<!

內容

!

 

 

17.6位置引數變數

 

17.6.1介紹

當我們執行一個shell指令碼時,如果希望獲取到命令列的引數資訊,就可以使用到位置引數變數

比如: ./myshell.sh 100 200,這個就是一個執行 shell 的命令列,可以在 myshell 指令碼中獲取到引數資訊

 


17.6.2基本語法

$n (功能描述: n為數字,$0代表命令本身,$1-$9 代表第一到第九個引數,十以上的引數,十以上的引數需要用

大括號包含,如${10} )
$*   (功能描述: 這個變數代表命令列中所有的引數,$*把所有的引數看成一個整體)
$@ (功能描述:這個變數也代表命令列中所有的引數,不過$@把每個引數區分對待)
$#   (功能描述:這個變數代表命令列中所有引數的個數)

 

 

 


17.6.3位置引數變數

案例:編寫一個 shell 指令碼 position.sh ,在指令碼中獲取到命令列的各個引數資訊

 

 

 

 

 

17.7預定義變數

17.7.1基本介紹

就是shell設計者事先已經定義好的變數,可以直接在shell指令碼中使用

 


17.7.2基本語法

1) $$ (功能描述:當前程序的程序號(PID))
2) $!  (功能描述:後臺執行的最後一個程序的程序號(PID))
3) $? (功能描述:最後一次執行的命令的返回狀態。如果這個變數的值為0,證明上一個命令正確執行;如果這個變數的值為非0 ( 具體是哪個數,由命令自己來決定),則證明上一個命令執行不正確了。)

 


17.7.3 應用例項

在一個shell指令碼中簡單使用一下預定義變數(指令碼名:preVar.sh)

 

#!/bin/bash
echo "當前執行的程序id=$$"
#以後臺的方式執行一個指令碼,並獲取他的程序號
/root/shcode/myshell.sh &
echo "最後一個後臺方式執行的程序id=$!"
echo "執行的結果是=$?"

 

 

 

17.8運算子

17.8.1 基本介紹

學習如何在shell中進行各種運算操作。

 


17.8.2 基本語法

1) “$((運算式))”或“$[運算式]”或者 expr m + n //expression 表示式
2) 注意 expr 運算子間要有空格,如果希望將 expr 的結果賦給某個變數,使用 ``
3) expr m - n
4) expr \*,/,%  乘,除,取餘


17.8.3應用例項oper.sh

案例1:計算 (2+3) X4 的值
案例2:請求出命令列的兩個引數[整數]的和 20 50

 

#!/bin/bash
#案例1:計算(2+3) X4的值
#使用第一種方式
RES1=$(((2+3)*4))
echo "res1=$RES1"
#使用第二種方式,推薦使用
RES2=$[(2+3)*4]
echo "res2=$RES2"
#使用第三種方式 expr
TEMP=`expr 2 + 3`
RES4=`expr $TEMP\* 4`
echo "temp=$TEMP"

echo "res4=$RES4"
#案例2: 請求出命令列的兩個引數[整數]的和 20 50
SUM=$[$1+$2]
echo "sum=$SUM"

 

 

 

 

17.9條件判斷

17.9.1判斷語句

 

基本語法
[ condition ] ( 注意 condition 前後要有空格)
#非空返回true,可使用$?驗證(0為true, >1為false )

應用例項
[ yxj ]   返回true
[ ]    返回false
[ condition ] && echo OK || echo notok  條件滿足,執行後面的語句

判斷語句
常用判斷條件
1)= 字串比較


2)兩個整數的比較
-lt   小於
-le  小於等於little equal
-eq 等於
-gt  大於
-ge  大於等於
-ne  不等於

3)按照檔案許可權進行判斷
-r   有讀的許可權
-w  有寫的許可權
-x   有執行的許可權


4)按照檔案型別進行判斷
-f   檔案存在並且是一個常規的檔案
-e  檔案存在
-d  檔案存在並是一個目錄
應用例項
案例1: "ok"是否等於"ok"
判斷語句:使用 =
案例2: 23 是否大於等於 22
判斷語句: 使用 -ge
案例3: /root/shcode/aaa.txt 目錄中的檔案是否存在
判斷語句:使用-f
程式碼如下:

 

 

 

 

 

 

17.10流程控制

17.10.1 if判斷

基本語法
if[ 條件判斷式 ]
then
程式碼
fi

或者,多分支

if[條件判斷式]
then
程式碼
elif [條件判斷式]
then
程式碼
fi


注意事項:[ 條件判斷式 ],中括號和條件判斷式之間必須有空格
應用例項 ifCase.sh
案例:請編寫一個shell程式,如果輸入的引數,大於等於60,則輸出"及格了",如果小於60,則輸出"不及格"

 

 

 

17.10.2 case語句


基本語法
case $變數名 in
"值1")
如果變數的值等於值1,則執行程式1

;;
"值 2")
如果變數的值等於值2,則執行程式2
;;
...省略其他分支...

*)
如果變數的值都不是以上的值,則執行此程式

;;
esac


應用例項 testCase.sh
案例1 :當命令列引數是1時,輸出"週一",是2時,就輸出"週二”,其它情況輸 出"other"

 

 

 

 

17. 10.3 for迴圈


基本語法1

for 變數 in 值1 值2 值3...

do
程式/程式碼
done
應用例項  testFor1.sh
案例1 : 列印命令列輸入的引數 [這裡可以看出 $* 和 $@ 的區別]


基本語法2
for(( 初始值;迴圈控制條件;變數變化 ))

do
程式/程式碼
done

 


應用例項  testFor2.sh
案例1 : 從1加到100的值輸出顯示

 

 

 

 

 

 

17.10.4 while迴圈


基本語法1
while [ 條件判斷式 ]

do
程式/程式碼
done
注意: while 和 [有空格,條件判斷式和 [也有空格


應用例項testWhile.sh
案例1 :從命令列輸入一個數n,統計從1+..+n 的值是多少?

#!/bin/bash
#案例1 :從命令列輸入一個數n,統計從1+..+n 的值是多少?
SUM=0
i=0
while[ $i -le $1 ]
do
  SUM=$[$SUM+$i]
  #i 自增
  i=$[$i+1]
done
echo "執行結果=$SUM"

 

 

 

 

 

17.11 read讀取控制檯輸入

17.11.1基本語法

read(選項)(引數)
選項:
-p: 指定讀取值時的提示符;
-t:  指定讀取值時等待的時間(秒),如果沒有在指定的時間內輸入,就不再等待了。。
引數
變數: 指定讀取值的變數名

 

 

17.11.2 應用例項testRead.sh

案例1:讀取控制檯輸入一個NUM1值
案例2:讀取控制檯輸入一個NUM2值,在10秒內輸入。
程式碼:

#!/bin/bash
#案例1:讀取控制檯輸入一個 NUM1 值
read-p "請輸入一個數 NUM1=" NUM1
echo "你輸入的 NUM1=$NUM1"
#案例2: 讀取控制檯輸入一個 NUM2 值,在10 秒內輸入。
read -t 10 -p "請輸入一個數 NUM2=" NUM2
echo "你輸入的 NUM2=$NUM2"

 

 

 

 

17.12函式

17.12.1函式介紹

shell程式設計和其它程式語言一樣,有系統函式,也可以自定義函式。系統函式中,我們這裡就介紹兩個。

 


17.12.2系統函式

basename 基本語法
功能:返回完整路徑最後 / 的部分,常用於獲取檔名
basename [pathname] [suffix]
basename [string] [suffx]  (功能描述: basename命令會刪掉所有的字首包括最後一個(‘/’)字元,然後將字串顯示出來。
選項:
suffix 為字尾,如果suffix被指定了,basename 會將 pathname 或 string 中的 suffix 去掉。

 

應用例項

案例1:請返回 /home/aa/test.txt 的"test.txt" 部分
basename /home/aaa/test.txt

dirname 基本語法
功能:返回完整路徑最後 / 的前面的部分,常用於返回路徑部分
dirmame檔案絕對路徑 (功能描述:從給定的包含絕對路徑的檔名中去除檔名(非目錄的部分),然後返回剩下的路徑(目錄的部分) )

應用例項
案例1:請返回 /home/aaa/test.txt 的 /home/aaa
dirname /home/aa/test.txt

 

 

17.12.3自定義函式

基本語法
[ function ] funname[()]
{
  Action;
  [return int;]
}

呼叫直接寫函式名: funname [值]

應用例項
案例1:計算輸入兩個引數的和(動態的獲取),getSum
程式碼

 

#!/bin/bash
#案例1:計算輸入兩個引數的和(動態的獲取),getSum

#定義函式 getSum
function getSum() {
  SUM=$[$n1+$n2]
  echo "和是=$SUM"
}

#輸入兩個值
read -p "請輸入一個數n1=" n1
read-p "請輸入一個數 n2=" n2
#呼叫自定義函式
getSum $n1 $n2

 

 

 

 

17.13Shell程式設計綜合案例

17.13.1需求分析

1) 每天凌晨 2:30 備份 資料庫 hspedu到 /data/backup/db
2) 備份開始和備份結束能夠給出相應的提示資訊
3) 備份後的檔案要求以備份時間為檔名,並打包成.tar.gz 的形式,比如: 2021-03-12_230201.tar.gz
4) 在備份的同時,檢查是否有10天前備份的資料庫檔案,如果有就將其刪除。
5) 畫一個思路分析圖

 

 

 

17.13.2 程式碼 /usr/sbin/mysql_db.backup.sh

#備份目錄
BACKUP=/data/backup/db
#當前時間
DATETIME=$(date +%Y-%m-%d_ %H%M%S)
echo $DATETIME
#資料庫的地址
HOST=localhost
#資料庫使用者名稱
DB_USER=root
#資料庫密碼
DB_PW=hspedu100
#備份的資料庫名
DATABASE=hspedu
#建立備份目錄,如果不存在,就建立
[ !-d "${BACKUP}/${DATETIME}" ] && mkdir -p "${BACKUP}/${DATETIME}"

#備份資料庫
mysqldump -u${DB_USER} -p${DB_PW} --host=${HOST} -q -R --databases ${DATABASE} |  gzip > ${BACKUP}/${DATETIME }/$DATETIME.sql.gz
#將檔案處理成 tar.gz
cd ${BACKUP}
tar -zcvf $DATETIME.tar.gz ${DATETIME}
#刪除對應的備份目錄
rm -rf ${BACKUP}/${DATETIME}
#刪除10天前的備份檔案
find ${BACKUP} -atime +10 -name "*.tar.gz" -exec rm -rf{}\;
echo "備份資料庫${DATABASE} 成功~"