精講shell基礎以及如何高效的學習shell編程



一、前言

1.1 爲何學習shell編程

Shell腳本語言是實現Linux/UNIX系統管理及自動化運維所必備的重要工具,Linux/UNIX系統的底層及基礎應用軟件的核心大部分涉及Shell腳本的內容。每個合格的Linux系統管理員或運維工程師,都須要熟練的編寫Shell腳本語言,並可以閱讀系統及各種軟件附帶的Shell腳本內容。只有這樣才能提高運維人員的工做效率,適應日益複雜的工做環境,減小沒必要要的重複工做,從而爲我的的職場發展奠基較好的基礎html

1.2 學好Shell編程所需的基礎知識

  • 可以熟練使用vim編輯器,熟悉SSH終端linux

  • 有必定的Linux命令基礎,至少須要掌握80個以上Linux經常使用命令,並可以熟練使用它正則表達式

  • 要熟練掌握Linux正則表達式及三劍客命令(grep,sed,awk)shell

1.3 如何學好Shel編程

  • 學好Shel編程的核心:多練-->多思考-->再練-->再思考,堅持如此循環便可!編程

  • 新手大忌:不可拿來主義,能夠模仿,可是要本身嚼爛了吃下去,不然會鬧肚子vim

  • 格言:你以爲會了並不必定會了,你認爲對的並不必定對的windows

你們要勤動手,自行完成學習筆記和代碼的書寫。經過每個小目標培養本身的興趣以及成就感bash


二、Shell腳本入門

2.1 什麼是Shell

  • Shell是一個命令解釋器,它在操做系統的最外層,負責直接與用戶對話服務器

    把用戶的輸入解釋給操做系統,並處理各類各樣的操做系統的輸出結果,輸出屏幕返回給用戶運維

  • 這種對話方式能夠是:
    1)交互的方式:從鍵盤輸入命令,經過/bin/bash的解釋器,能夠當即獲得shell的迴應
    2)非交互的方式:腳本

下圖×××部分就是命令解釋器shell


Shell的英文意思是貝殼的意思,命令解釋器Shell像一個貝殼同樣包住系統核心

Shell執行命令分爲兩種方式:

  • 內置命令:

    如講過的cd,pwd,exit和echo等命令

    當用戶登陸系統後,shell以及內置命令就被系統載入內存,而且一直運行


  • 通常命令:如ls,磁盤上的程序文件-->調入-->執行命令

2.2 什麼是Shell 腳本

當linux命令或語句不在命令行下執行(嚴格說,命令行也是shell)

而是經過一個程序文件執行時,該程序就被稱爲Shell腳本或Shell程序
用戶能夠在Shell腳本中敲入一系列的命令及語句組合;這些命令

變量和流程控制語句等有機的結合起來就造成一個功能強大的Shell腳本

首先先帶領你們寫一個清空/var/log/messages日誌的腳本

咱們須要先想明白幾個問題:
1)日誌文件在哪?
/var/log/messages
2)用什麼命令能夠清空文件?
> 重定向
3)寫一個簡單的shell腳本

#! /bin/bash

cd /var/log/

>messages

4)怎樣執行腳本?
# sh /server/scripts/log.sh

有沒有考慮到:

  • 有沒有腳本放在統一的目錄

/server/scripts目錄下

  • 權限:用哪一個用戶執行文件

須要對用戶作判斷

  • 清空錯文件怎麼辦,該如何辦?

  • 錯誤提示:有沒有成功知不知道?

  • 腳本的通用性

小結:

  • Shell就是命令解釋器。==>翻譯官

  • Shell腳本==>命令放在腳本里


三、Shell腳本的創建和執行

3.1 Shell腳本的創建

推薦使用vim編輯器編輯腳本,能夠事先作個別名

# echo "alias vi=vim">>/etc/profile
# source /etc/profile

3.1.1腳本開頭第一行

規範的Shell腳本第一行會指出由哪一個程序(解釋器)來執行腳本中的內容

在linux bash編程中通常爲:

#!/bin/bash或#!/bin/sh

其中開頭的「#!」又稱爲幻數,在執行Shell腳本的時候

內核會根據「#!」後的解釋器來肯定哪一個程序解釋腳本中的內容

注意:這一行必須在每一個腳本頂端的第一行,若是不是第一行則爲腳本註釋行

3.1.2 sh和bash的區別

# ll /bin/shlrwxrwxrwx. 1 root root 4 Dec 23 20:25 /bin/sh -> bash
# sh是bash的軟連接,推薦標準寫法#!/bin/bash

能夠看一下系統自帶的腳本的寫法

head -1 /etc/init.d/*

3.1.3 腳本註釋

在Shell腳本中,跟在#後面的內容表示註釋。註釋部分不會被執行,僅給人看

註釋能夠自成一行,也能夠跟在命令後面,與命令同行。要養成寫註釋的習慣,方便本身與他人

最好不用中文註釋,由於在不一樣字符集的系統會出現亂碼

3.2 Shell腳本的執行

3.2.1 Shell腳本執行的幾種方式

1)bash scripts-name或sh script-name(推薦使用)

這種方法是當腳本自己沒有可執行權限時常使用的方法

2)path /script-name 或./scripts-name(全路徑或當前路徑執行腳本)
這種方法首先須要給腳本文件可執行權限

3)source scripts-name或. scripts-name #注意「.」點號,且點號後有空格
source 或.在執行這個腳本的同時,能夠將腳本中的函數和變量加載到當前shell

3.3 Shell腳本開發的規範和習慣

1)開頭指定腳本解釋器
2)開頭加版本版權等信息,可配置~/.vimrc文件自動添加
3)腳本不要用中文註釋,儘可能用英文註釋
4)腳本以.sh爲擴展名
5)放在統一的目錄
6)代碼書寫優秀習慣

a,成對的內容一次性寫出來,防止遺漏,如[],'',""等
b,[]兩端要有空格,先輸入[]退格,輸入2個空格,再退格寫
c,流程控制語句一次書寫完,再添加內容

if 條件
    then
      內容
fi

d,經過縮進讓代碼易讀
e,腳本中的引號都是英文狀態下的引號,其餘字符也是英文狀態

好的習慣可讓咱們避免不少沒必要要的麻煩,提升工做效率


四、Shell環境變量

4.1 什麼是變量

變量就是用一個固定的字符串(也多是字符數字等的組合),替代更多更復雜的內容

這個內容裏可能還會包含變量和路徑,字符串等其餘內容。變量的定義是存在內存中

x=1
y=2

4.2 變量類型

變量分爲兩類:
1)環境變量(也可稱爲全局變量)

能夠在建立他們的Shell及派生出來的子shell中使用

環境變量又能夠分爲自定義環境變量和bash內置的環境變量

2)局部變量(普通變量):

只能在建立他們的shell函數或shell腳本中使用,還記得前面的$user?咱們建立的通常都是普通變量

4.2.1 環境變量

  • 環境變量用於定義Shell的運行環境,保證Shell命令的正確執行,Shell經過環境變量來肯定登陸用戶名,命令路徑,終端類型,登陸目錄等,全部的環境變量都是全局變量,可用於全部子進程中

    包括編輯器,shell腳本和各種應用。但crond計劃任務除外,還須要從新定義環境變量

  • 環境變量能夠在命令行中設置,但用戶退出時這些變量值也會丟失,所以最好在用戶家目錄下的

    .bash_profile文件中或全局配置/etc/bashrc,/etc/profile文件或者/etc/profile.d/目錄中定義

    將環境變量放入profile文件中,每次用戶登陸時這些變量值都將被初始化

  • 一般,全部環境變量均爲大寫。環境變量應用於用戶進程前,都應該用export命令導出

    例如:export chensiqi=1

  • 有一些環境變量,如HOME,PATH,SHELL,UID,USER等,在用戶登陸前就已被/bin/login

    程序設置好了。一般環境變量定義並保存在用戶家目錄下的.bash_profile或/etc/profile文件中

4.2.1 局部變量

定義局部變量

局部變量在用戶當前的shell生存期的腳本中使用。例如,局部變量test取值爲test18

這個值只在用戶當前shell生存期中有意義。若是在shell中啓動另外一個進程或退出,局部變量test值將無效

普通字符串變量定義

變量名=value
變量名=‘value’
變量名=「value」

shell中變量名及變量內容的要求

  • 通常是字母,數字,下劃線組成,且以字母開頭

    變量的內容,可使用單引號或雙引號印起來,或不加引號

  • 雖然變量能夠如下劃線開頭,但相似這種變量都是比較特殊的,都是系統本身用的。咱們儘可能少用

小結:

1)CMD=ls的ls兩側的符號是鍵盤tab鍵上面的,不是單引號
2)在變量名前加$,能夠取得此變量的值,使用echo或printf命令能夠顯示變量的值

    $A和$(A)寫法不一樣,效果同樣,推薦後面的寫法
3)${WEEK}DAY若變量和其餘字符組成新的變量就必須給變量加上大括號{}.
4)養成將全部字符串變量用雙引號括起來使用的習慣,減小編程遇到的怪異錯誤。「$A」和「${A}」

4.3 變量名及變量內容定義小結

  1. 變量名只能由字母,數字,下劃線組成,且以字母開頭

  2. 規範的變量名寫法定義:見名知意
    a,testAge=1 <==每一個單詞首字母大寫
    b,test_age=1 <==每一個單詞之間用「-」
    c,testAgeSex=1 <==駝峯語法:首個單詞字母小寫,其他單詞首字母大寫

  3. =號的知識,a=1中的等號是賦值的意思,比較是否是相等爲「==」

  4. 打印變量,變量名前接$符號,變量名後接字符的時候,要用大括號括起來

注意:
  1. 變量內容引用方法,通常爲雙引號,簡單連續字符能夠不加引號,但願原樣輸出,使用單引號

  2. 變量內容是命令,要用反引號``或者$()把變量括起來使用


五、Shell特殊變量

5.1 位置變量

$0 獲取當前執行的shell腳本的文件名,若是執行腳本帶路徑那麼就包括腳本路徑

$n 獲取當前執行的shell腳本的第n個參數值,n=1..9,當n爲0時
   表示腳本的文件名,若是n大於9用大括號括起來{10},參數以空格隔開
   
$# 獲取當前執行的shell腳本後面接的參數的總個數
$0 獲取當前執行的shell腳本的文件名,包括路徑

5.2 進程狀態變量

$? 獲取執行上一個指令的返回值(0爲成功,非零爲失敗)

5.2.1 $?測試

# echo $?
0
# cd /rrr
-bash: cd: /rrr: No such file or directory
# echo $?
1

$? 返回值參考
0  表示運行成功
2  權限拒絕
1~125 表示運行失敗,腳本命令,系統命令錯誤或參數傳遞錯誤
126 找到該命令,但沒法執行
127 未找到要運行的命令
128 命令被系統強制結束

生產環境:
1)用於判斷命令,腳本或函數等程序是否執行成功
2)若在腳本中調用執行「exit數字」,則會返回這個數字給「$?」變量
3)若是在函數中使用「return 數字」,則會以函數返回值的形式傳給「$?」


六、變量的數值計算

6.1 (())用法(經常使用於簡單的整數運算)

算數運算符號

wKiom1kZQtGgeh_0AAAyLL93HLU772.png-wh_50

# ((a=1+2**3-4%3))使用方法:

# echo $a
8
# b=$((1+2**3-4%3))
# echo $b
8
# echo $((1+2**3-4%3))
8

小結:
1)「(())」在命令行執行時不須要$符號,可是輸出須要$符號
2)「(())」裏全部字符之間有無或多個空格沒有任何影響

6.2 $[]的用法

# echo $[2+3]
5
# echo $[2*3]
6


七、腳本中定義變量

7.1 腳本中直接賦值

# cat test.sh 
#!/bin/env bash

a=6
b=2
echo "a-b =$(($a - $b))"
echo "a+b =$(($a + $b))"
echo "a*b =$(($a * $b))"
echo "a/b =$(($a / $b))"
echo "a**b =$(($a ** $b))"
echo "a%b =$(($a % $b))"

7.2 命令行傳參

# cat test.sh 
#!/bin/env bash

a=$1   #不須要把後面的$a,$b都改
b=$2
echo "a-b =$(($a - $b))"
echo "a+b =$(($a + $b))"
echo "a*b =$(($a * $b))"
echo "a/b =$(($a / $b))"
echo "a**b =$(($a ** $b))"
echo "a%b =$(($a % $b))"


八、條件測試

什麼是條件測試呢?
簡單理解,判斷某些條件是否成立,成立執行一種命令,不成立執行另一種命令

8.1 條件測試語法

格式:[ <測試表達式> ] 你們要掌握着一種,注意測試表達式兩邊要留空格

8.2 測試表達式

好習慣:先敲一對[],而後退格輸入2個空格[],最後再回退一個空格開始輸入[ -f file ]

# [ -f /etc/hosts ] && echo 1 || echo
1
# [ -f /etc/hosts1 ] && echo 1 || echo 0
0
# [ ! -f /etc/hosts1 ] && echo 1 || echo 0
1

# 在作測試判斷時,不必定用上面的方法,用下面的寫一半方法更簡潔
# [ -f /etc/hosts ] && echo 1
1
# [ -f /etc/hosts1 ] || echo 0
0

# 系統腳本
# vi /etc/init.d/nfs
....
[ -x /usr/sbin/rpc.nfsd ] || exit 5
[ -x /usr/sbin/rpc.mountd ] || exit 5
[ -x /usr/sbin/exportfs ] || exit 5

8.3 經常使用文件測試操做符號

wKioL1kZQxvhdldWAABr87ng0CM747.png-wh_50

8.4 字符串測試操做符

比較兩個字符串是否相同,字符串長度是否爲零,字符串是否爲NULL。Bash區分零長度字符串和空字符串

|經常使用字符串測試操做符|說明|
|--|--|
|-z "字符串"|若串長度爲0則真,-z理解爲zero|
|-n 「字符串」|若串長度不爲0則真,-n理解爲no zero|
|「串1」=「串2」|若串1等於串2則真,可使用「==」代替「=」|
|「串1」!="串2"|若串1不等於串2則真,但不能使用「!==」代替「!=」|

特別注意,以上表格中的字符串測試操做符號務必要用「」引發來

[ -z "$string"]字符串比較,比較符號兩端最好有空格,參考系統腳本

[ "$password" = "john" ]

提示:
[,"password",=,"join",]之間必須存在空格

8.5 整數二元比較操做符

wKiom1kZQ0aT9Q9IAAAfmJK0EfY124.png-wh_50

8.6 邏輯操做符在[]中能夠用>和<,但須要用\轉義,雖然不報錯,但結果不對。但仍是不要混用!

wKiom1kZQ23iuWE7AAASCjQ2wJI641.png-wh_50

小結:
1)多個[]之間的邏輯操做符是&&或||
2)&&前面成功執行後面
3)||前面不成功執行後面


九、if條件語句

9.1 if單分支條件語句

if [ 條件 ]
    then
        指令
fi
或
if [ 條件 ];then
    指令
fi

提示:分號至關於命令換行,上面兩種語法等同

9.2 if 雙分支條件語句

if [ 條件 ]
    then
        指令
    else
        指令
fi

9.3 多分支if語句

if [ 條件1 ];then

    指令1

elif [ 條件2 ];then

    指令2

elif [ 條件3 ];then

    指令3

elif [ 條件4 ];then

    指令4

else

    指令n

fi


十、case 結構條件句

10.1 case結構條件句語法

case "字符串變量" in
    值1)
        指令1
        ;;
    值2)
        指令2
        ;;
    *)
        指令
esac

注意:case語句至關於一個if的多分支結構語句

case 語句小結:
1)case語句就至關於多分支的if語句。case語句的優點是更規範,易讀
2)case語句適合變量的值少,且爲固定的數字或字符串集合
3)系統服務啓動腳本傳參的判斷多用case語句

十一、循環語句(while/for)

11.1 循環語句語法

11.1.1 while條件語句

while 條件
    do
        指令
done

11.1.2 for循環結構語法

for 變量名 in 變量取值列表
    do
        指令...
done

11.2 while語句

休息命令:sleep 1 休息一秒,usleep 1000000休息1秒單位微妙

11.2.1 守護進程

# cat test.sh 
#!/bin/bash

while true
do
    uptime >> /var/log/uptime.log
    sleep 2
done

# while true 表示條件永遠爲真,所以會一直運行,像死循環同樣

# cat /var/log/uptime.log 
 23:01:57 up  8:33,  2 users,  load average: 0.04, 0.03, 0.05
 23:01:59 up  8:33,  2 users,  load average: 0.04, 0.03, 0.05
 23:02:01 up  8:33,  2 users,  load average: 0.04, 0.03, 0.05

11.2.2 從1加到100

# cat test.sh 
#!/bin/bash
i=1
sum=0
while [ $i -lt 100 ]
do
    ((sum=sum+i))
    ((i++))
done
echo $sum

11.2.3 倒計時

# cat test.sh 
#!/bin/bash

i=10
while [ $i -gt 0 ]
do
    echo $i
    sleep 1
    ((i--))
done

11.3 防止腳本執行中斷的方法

1)sh while01.sh & #放在後臺執行
2)screen 分離 ctrl+a+d 查看screen -ls進入screen -r num
3)nohup while01.sh &

11.4 for循環語句

11.4.1 打印列表元素

# cat test.sh 
#!/bin/bash

for i in 5 4 3 2 1   #用空格隔開
do
    echo $i
done

# sh test.sh 
5
4
3
2
1

# for i in {5..1};do echo $i;done
5
4
3
2
1

# echo 10.1.1.{1..10}
10.1.1.1 10.1.1.2 10.1.1.3 10.1.1.4 10.1.1.5 10.1.1.6 10.1.1.7 10.1.1.8 10.1.1.9 10.1.1.10

# for i in `seq 5 -1 1`;do echo $i;done
5
4
3
2
1
#循環執行命令n次
# for i in `seq 100`;do curl -I baidu.com;done

11.4.2 開機啓動項優化

# cat test.sh 
#!/bin/bash

LANG=en
for i in `chkconfig --list|grep "3:on"|awk '{print $1}'`
do
    chkconfig $i off
done

for name in sshd rsyslog crond network sysstat
do
    chkconfig $name on
done

11.4.3 在/test目錄批量建立文件

#!/bin/bash

Path=/test
[ -d "$Path" ] || mkdir -p $Path
for i in `seq 10`
do
    touch $Path/test_$i.html
done

11.4.4 批量更名

# cat test.sh 
#!/bin/bash
$Path=/test
[ -d "$Path" ] || mkdir -p $Path
for file in `ls $Path`
do
    mv $file `echo $file|sed -r 's#test(.*).html#linux\1.HTML#g'`
done

11.4.5 批量建立用戶並設置密碼

# cat test.sh 
#!/bin/bash

User=test
Path=/tmp

for user in ${User}{01..10}
do
    useradd $user >/dev/null 2>&1
    if [ ! $? -eq 0 ];then
        echo "$user created faile!"
        echo "scripts begin to rollback!"
        for i in ${User}{01..10}
        do
            userdel -r $i >/dev/null 2>&1
            [ $? -eq 0 ] || exit 1
        done
        echo >$Path/user_passwd
        exit 1
    else
        passWD=`echo $RANDOM|md5sum|cut -c1-8`
        [ -d $Path ] || mkdir $Path
        echo $passWD | passwd --stdin $user
        echo "$user:$passWD">>$Path/user_passwd
    fi
done

11.4.6 獲取當前目錄下的目錄名作爲變量列表打印輸出

# cat /server/scripts/test.sh
#!/bin/bash

Path=`pwd`
echo $Path
for filename in `ls`
do
    [ -d ${Path}/${filename} ] && echo $filename
done

11.4.7 九九乘法表

# cat /server/scripts/test.sh 
#!/bin/bash

for ((i=1;i<10;i++))
do
    for ((j=1;j<=i;j++))
    do
        echo -n "$i * $j = $((i*j))"
        echo -n " "
    done
    echo " "
done

# sh /server/scripts/test.sh

11.5 break continue exit return

11.5.1 break continue exit 對比

break continue exit用於循環結構中控制虛幻(for,while,if)的走向

wKiom1kZQ_mR6opeAAA8mJhdKbA337.png-wh_50

# cat /server/scripts/test.sh

11.5.2 break

#!/bin/bash

for ((i=0;i<=5;i++))
do
    [ $i -eq 3 ] && break
    echo $i
done
echo "ok"

# sh /server/scripts/test.sh
0
1
2
ok

11.5.3 continue

# cat /server/scripts/test.sh
#!/bin/bash

for ((i=0;i<=5;i++))
do
    [ $i -eq 3 ] && continue
    echo $i
done
echo "ok"

# sh /server/scripts/test.sh
0
1
2
4
5
ok

11.5.4 exit

# cat /server/scripts/test.sh
#!/bin/bash

for ((i=0;i<=5;i++))
do
    [ $i -eq 3 ] && exit 2
    echo $i
done
echo "ok"

# sh /server/scripts/test.sh
0
1
2

# echo $?
2

11.5.5 return

# cat /server/scripts/test.sh
#!/bin/bash

function xxxx {

    for ((i=0;i<=5;i++))
    do
        [ $i -eq 3 ] && return 7
        echo $i
    done
    echo "ok"

}

xxxx
echo $?

# sh /server/scripts/test.sh
0
1
2
7


十二、shell腳本的調試

  1. 使用dos2unix處理腳本

從windows編輯的腳本到Linux下須要使用這個命令
dos2unix windows.sh

  1. 使用echo命令調試

在變量讀取或修改的先後假如echo $變量,也可在後面使用exit退出腳本,這樣能夠不用註釋後邊代碼

  1. 利用bash的參數調試

sh [-nvx]
-n:不會執行該腳本,僅查詢腳本語法是否有問題,並給出錯誤提示

可用於生產服務器那些只能執行一次不可逆的腳本
-v:在執行腳本時,先將腳本的內容輸出到屏幕上而後執行腳本

若是有錯誤,也會給出錯誤提示。(通常不用)
-x:將執行的腳本內容及輸出顯示到屏幕上,經常使用

shell腳本調試技巧小結:
1)要記得首先用dos2unix對腳本格式化
2)直接執行腳本根據報錯來調試,有時報錯不許確
3)sh -x調試整個腳本,顯示執行過程
4)set -x和set +x調試部分腳本(在腳本中設置)
5)echo輸出變量及相關內容,而後緊跟着exit退出

    不執行後面程序的方式,一步步跟蹤腳本,對於邏輯錯誤比較好用
6)最關鍵的時語法熟練,編碼習慣,編程思想,將錯誤扼殺在萌芽中,減輕調試負擔,提升效率


1三、運維人員如何學好shell編程

核心:練-->想-->再練-->再想!


1.基本語法,敲n+1遍。爲何不是n遍那,由於n遍是你剛開始爲了編程而努力的幾天
  1是說你之後要天天都要寫寫想一想,至少是要看看


2.各類基本語法,if多種判斷都要會,這樣作不是爲了什麼都要學

   而是爲了看懂別人的代碼。 這個要寫一段時間,各類都用


3.解決上邊說的問題,各類語法都要學的問題

   如今是不要作各類語法的程序,與上邊;相反,造成本身風格,if用一種


4.從簡單作起,簡單判斷,簡單循環


5.多找幾個例子分析一下,不要光看,會了。當你閉上眼睛時候,你還能寫出來嗎?


6.對於問題分析造成編程思惟,就是若是要用到編程的問題,腳本的問題 
   可否先把大問題分解,當你看到很大的問題,能分析到一個個單元

   但到大的方面,函數,而後是判斷循環,而後是命令組合

   你就會了編程,通常的問題,只要讓你在機器上調試,就能寫出來


7.編程變量名字規範,駝峯表示,iptTmpAsdfDd

   記住初期時候,不要去看大的腳本,要從小問題,從小方面

   當你以爲小的方面就是判斷,循環等在你腦子裏瞬間就能出來時候

   再開始大方面;聽一些高手們說,初期最好的學習方法就是多敲和分解問題練習


最高的編程自我感受是:問題分析分解快速完整
完整性,就是判斷出各類可能性,高效率,高性能,1+2+3...+100 =(1+100)*(100/2)/2


我的總結:

shell做爲一門通用的系統語言,是全部運維人員都必需要了解和掌握的,經過shell能幫助咱們解決平常工做中不少重複、繁瑣的工做,可是shell的基礎就是系統命令,所以,只有掌握了系統命令的原理和使用方法,shell才能運行起來


想學習shell編程,得慢慢來,其中基本的命令你必須得熟練掌握

而後再學習一些結構化命令,而後再學習編輯器、正則表達式等

其中vim sed awk grep等命令必定要學好,等掌握差很少的時候,能夠拿一些項目來作

學好了對你受益無窮,學shell編程不要急;要記住,一口吃不了一個胖子,只有一步一步學,相信你會掌握它的!

相關文章
相關標籤/搜索