第14章,Shell腳本編程進階

更多內容請點擊:shell

Linux學習從入門到打死也不放棄,徹底筆記整理(持續更新,求收藏,求點贊~~~~) 
編程

https://blog.51cto.com/13683480/2095439centos


第14章,Shell腳本編程進階數組


本章內容:bash

               條件判斷服務器

               循環ssh

               信號捕捉編程語言

               函數ide

               數組模塊化

               高級字符串操做

               高級變量

               Expect

 

過程式編程語言執行方式:

               順序執行,選擇執行,循環執行

               

條件選擇-----------------------------------------------------------------------

 

if語句:

               結構:     可嵌套

               單分支:

                            if 判斷條件;then

                                    條件判斷爲真的執行代碼

                             fi

               雙分支:

                            if 判斷條件;then

                                    條件判斷爲真的執行代碼

                                    (此段若想爲空,使用":")

                             else

                                    條件判斷爲假的執行代碼

                             fi

               多分支:

                            if 條件判斷1;then

                                   cmd..

                            elif  條件判斷2;then

                                   cmd..

                            elif  條件判斷3;then

                                   cmd..

                             else

                                    以上條件全爲假的分支代碼

                             fi

        

case語句:

               格式:

                            case  變量引用 in

                            pat1)

                                           分支1

                                           ;;

                            pat2)

                                           分支2

                                           ;;

                             ...

                            *)

                                           默認分支

                                           ;;

                             esac

 

               注意:     case支持glob風格的通配符

                                   *             任意長度任意字符

                                   ?           任意單個字符

                                   [abc]       指定範圍內的任意單個字符

                                   a|b          a或b

                    

 

循環執行------------------------------------------------------------------------

               將某代碼段重複屢次運行

               重複運行多少次

                            循環次數事先已知

                            循環次數事先未知

               有進入條件和退出條件

               for,while,until

        

for循環

               格式:     

                            for 變量名 in 列表;do

                                    循環體代碼

                             done

               機制:

                             依次將列表中的元素賦值給"變量名"

                             每次賦值後即執行一次循環體,直到列表中的元素耗盡,循環結束

               列表生成方式:

                            1     直接給出列表

                            2     整數列表

                                          {1..10..2}

                                          $(seq  1 2 10)

                            3     返回列表的命令

                                           $(cmd)

                            4     使用glob,如:*.sh

                            5     變量引用

                                           $@,$*

                             

while循環

               格式:

                            while CONDITION;do

                                    循環體

                             done

               CONDITION :

                            循環控制條件

                             進入循環以前,先作一次判斷

                             每一次循環以後會再次作判斷

                            條件爲true,則執行一次循環,直到條件測試狀態爲false 終止循環

               所以:     CONDITION通常應該有循環控制變量,而此變量的值會在循環體不斷的被修正

               進入條件:CONDITION爲true        

               退出條件:CONDITION爲false

               

until循環

               格式:

                            until CONDITION;do

                                    循環體

                             done

               進入條件:CONDITION 爲  false

               退出條件:CONDITION 爲  true

               

循環控制語句:

               用於循環體中

               continue [N] 默認爲1

                             用於循環體中,提早結束第N層的本輪循環,而直接進入下一輪判斷

                            所在層爲第1層

 

               break [N] 默認爲1

                             用於循環體中,提早結束第N層循環,所在層爲第1層

               

               shift [N] 默認爲1

                            用於將參數列表list 左移指定的次數,默認1次

                            參數列表list 一旦被移動,最左端的那個參數就從列表中刪除。

                             while循環遍歷位置參數列表時,經常使用到shift

                             

建立無限循環:

               1     while true;do

                            循環體代碼

                     done

                    

               2     until false;do

                            循環體

                     done

 

 

特殊用法:

               

        while 循環的特殊用法(遍歷文件的每一行)

                                   while read  變量名;do

                                           循環體代碼

                                   done <  /file

                     一次讀取file 文件中的每一行,且將行賦值給變量

               

                     PS:   也可使用   cmd |while read;do

                                                  循環體

                                           done

                      可是循環中的數組值貌似不能輸出,即如在done以後echo 數組中的值爲空 ,須要注意

        

        雙小括號方法,即((....))格式,也能夠用於算術運算

                     也能夠是bash實現C語言風格的變量操做

                                    i=10

                                    ((i++))

        

        for 循環 的特殊格式:

                      for((控制變量初始化;條件判斷表達式;控制標量的修正表達式));do

                            循環體代碼

                     done

                    

                     如:       for ((i=1;i<=10;i++));do

                                          echo  $i

                                    done

                     控制變量初始化:

                                    僅在運行到循環代碼段時執行一次

                     控制變量的修正表達式:

                                    條件判斷表達式:進入循環先作一次條件判斷,true則進入循環

                                    每輪循環結束會先進行控制變量的修正運算,然後在作條件判斷

 

                    

select循環與菜單:

               格式:     

                            select  變量  in  列表;do

                                    循環體命令

                             done

                            select  循環主要用於建立菜單,按數字順序排列的菜單項將顯示在標準錯誤上,並顯示

                                           PS3提示符,等待用戶輸入

                             用戶輸入菜單列表上的某個數字,執行相應的命令

                             用戶輸入被保存在內置變量REPLY中

                     PS2:     多行重定向的提示符

                     PS3:     select的提示符    

                     REPLY     保存select的用戶輸入

                    

               select與case

                             select是個無限訓話,所以要記住用break命令退出循環,或用exit命令終止腳本。

                            也能夠按Ctrl+c退出循環

                            select  常常和case聯合使用

                            與for循環相似,能夠省略in list ,此時使用位置參量

               

trap 信號捕捉:

               trap ‘觸發指令’信號

                             自定義進程收到系統發出的指定信號後,將執行觸發指令,而不會執行原操做

               trap ''信號

                            忽略信號的操做

               trap '-' 信號

                            恢復原信號的操做

               trap -p

                             列出自定義信號操做

               

               注意事項:

                            信號:    格式能夠是 int INT sigint SIGINT 2   

                             信號捕捉以後,雖然不會馬上結束腳本,可是腳本當前運行的命令卻會被終止

                            如:       trap 'echo trap a sig2'  2

                                          sleep  10000

                                          ping  192.168.0.1

                                    若是捕捉到2信號,不會退出腳本,可是sleep會被打斷,而繼續執行ping命令

                                    

函數:------------------------------------------------------------------------------

 

函數介紹:

                            函數function是由若干條shell命令組成的語句塊,實現代碼重用和模塊化編程

                            它與shell程序形式上是類似的,不一樣的是它不是一個單獨的進程,不能獨立運行,

                     而是shell程序的一部分

                            函數和shell程序區別在於:

                                           shell程序在子shell中運行

                                           而shell函數在當前shell中運行。所以在當前shell中,函數能夠對shell變量

                                           進行修改

 

定義函數:

                             函數由兩部分組成:函數名和函數體

                            help  function

                                    語法1:

                                                  f_name(){

                                                         函數體

                                                  }

                                    語法2:

                                                  function f_name()

                                                  {

                                                         函數體

                                                  }

                                    語法3:

                                                  function f_name{

                                                  函數體

                                                  }

                             能夠交互式環境下定義函數,如:

                                           [root@centos6 ~/bin]$func_name1(){

                                          >  echo nihao

                                          >  echo wohenhao

                                          >  ping  -c1 -w1  192.168.0.1   

                                          >  }

                                           [root@centos6 ~/bin]$func_name1

                                           nihao

                                           wohenhao

                                           connect: Network is unreachable

                             可將函數放在腳本文件中做爲它的一部分

                             可放在只包含函數的單獨文件中

 

函數調用:

                             函數只有被調用纔會執行

                             函數名出現的地方,會被自動替換爲函數代碼

                            函數的生命週期:

                                           被調用時建立,返回時終止

                             在腳本中用戶前必須定義,所以應該將函數定義放在腳本開始部分,直至shell首次

                             發現它以後才能使用

                             調用函數僅使用其函數名便可

 

函數返回值:

                             函數由兩種返回值:

                                           函數的執行結果返回值:

                                                         1     使用echo等命令進行輸出

                                                         2     函數體中調用命令的輸出結果

                                           函數的退出狀態碼:

                                                         1      默認取決於函數中執行的最後一條命令的退出狀態碼

                                                         2     自定義退出狀態碼,return命令

                                          return  :        從函數中返回,用最後狀態命令決定返回值

                                                                return 0 無錯誤返回

                                                                return 1-255 有錯誤返回

                                    

刪除函數:

                            unset  func_name1

 

函數文件:

               建立函數文件:

                            #!/bin/bash

                            # function.main

                            f_hello()

                             {

                                   echo  helio

                             }

                            f_func2(){

                                    ...

                             }

                             ...

               系統自帶函數文件:/etc/rc.d/init.d/functions    

               

               使用函數文件:

                            能夠將進程使用的函數存入函數文件,而後將函數文件載入shell

                             文件名可任意選取,但最好與相關任務有某種聯繫,如  function.main

                            通常函數文件載入shell,就能夠在命令行或腳本中調用函數,

                            可使用set命令查看全部定義的函數,其輸出列表包括已經載入shell的全部函數

                             若要改動函數,首先用unset命令從shell中刪除函數,改動完畢後,再從新載入此文件

 

               載入函數:

                             要想使用已建立好的函數文件,要將他載入shell

                            使用

                                   .  /path/filename

                                   source  /path/filename

                    

               若是使用source 載入函數以後,對函數文件的某個函數作了修改,須要unset函數以後從新載入

                            unset  func_name1

                            或者exit 從新登陸而後再次source

               

               默認本shell進程有效,如需函數子進程有效,需聲明

                            export -f func_name  

                            declare  -xf

               如需查看當前全部的全局函數

                            export -f  或 declare -xf

                     例如:

                            [root@centos6  ~/bin]$export -f func_release

                            [root@centos6  ~/bin]$export -f

                            func_release ()  

                            {  

                                   declare  rel=$(cat /etc/centos-release|tr -dc [0-9]|cut  -c1);

                                   echo  $rel

                             }

                            declare -fx  func_release

                            [root@centos6  ~/bin]$

                    

函數參數:

               函數能夠接受參數:

                             調用函數時,在函數名後面以空白分隔給定參數列表便可;

                            例如 func_name arg1 arg2 ...

               在函數體當中,可使用$1,$2..調用這些參數;還可使用$@,$*,$# 等特殊變量

               注意區分腳本的位置參數和傳遞給函數的位置參數

               

函數變量:

               變量做用域:

                            環境變量:    當前shell和子shell有效

                            本地變量:    只在當前shell進程有效,爲執行腳本會啓動專用shell進程;

                                                  所以,本地變量的做用範圍是當前shell腳本程序文件,包括腳本中的函數

                            局部變量:     函數的生命週期;函數結束時變量會被自動銷燬

               注意:     如函數中的變量名同本地變量,使用局部變量

               函數中定義局部變量:

                            local  name=

                            declare name=            declare自帶局部變量屬性

                            declare -ig  在函數中定義普通變量,centos6不支持

 

函數遞歸:

                             函數直接或間接調用自身

                            注意遞歸層數

               

               函數遞歸示例:

                     階乘是基斯頓·卡曼於 1808 年發明的運算符號,是數學術語

                     一個正整數的階乘(factorial)是全部小於及等於該數的正整數的積,而且有0的

                     階乘爲1,天然數n的階乘寫做n!

                                   n!=1×2×3×...×n

                                    階乘亦能夠遞歸方式定義:0!=1,n!=(n-1)!×n

                                   n!=n(n-1)(n-2)...1

                                   n(n-1)! =  n(n-1)(n-2)!   

               示例:

                      fact.sh

                            #!/bin/bash

                            func_factorial()

                             {

                            if [ $1 = 0 ];then

                                          echo  1

                            else  

                                          echo  $[$1*`func_factorial $[$1-1]`]                                                   

                             fi

                             }

                            func_factorial  $1

               

fork×××:

                      fork×××是一種惡意程序,它的內部是一個不斷fork進程的無限循環,實質是一個簡單

                      的遞歸程序。因爲程序是遞歸的,若是沒有任何顯示,這會致使整個簡單的程序迅速

                     耗盡系統全部資源

        

               函數實現:

                            :(){  :|:&};: 

                            bomb(){ bomb|bomb&};bomb

               腳本實現:

                            cat  bomb.sh

                            #!/bin/bash

                            ./$0|./$0&

               多種語言版本             

 

數組---------------------------------------------------------------------------------

               變量:     存儲單個元素的內存空間

               數組:     存儲多個元素的連續的內存空間,至關於多個變量的集合

               數組名和索引:

                     索引:編號從0開始,屬於數值索引

                      bash4.0版本以後,索引能夠支持使用自定義的格式,而不只是數值格式,即爲關聯索引

                      bash中的數組支持稀疏格式(索引不連續)

               聲明數組:

                            declare -a array_name

                            declare -A  ARRAY_NAME 關聯索引

                            彼此不可互相轉化

                             

數組賦值:

               數組元素的賦值:

                     1     一次只賦值一個元素

                             array_name[index]=VALUE

                            如:

                                   weekdays[0]="sunday"

                                   weekdays[4]="thursday"

                     2     一次賦值所有元素

                            array_name=("VAL1" "val2" "val3"...)

                     3     只賦值特定元素

                            array_name=([0]=varl [3]=val2...)

                     4     交互式數組值對賦值

                            read -a array_name1

                            如:      

                                           [root@centos7 ~]$read -a  array_name1

                                          monday  tusday wensday thursday

                                           [root@centos7 ~]$echo  ${array_name1[@]}

                                          monday  tusday wensday thursday

               注意:

                     若是先賦值單個元素array[0]=a,

                            再使用賦值所有 array=(b c d) 或者特定賦值 array=([1]=e [2]=f  [3]=g)    

                            會使以前單個元素array[0]被覆蓋消失

                             

                      索引數組能夠無需聲明直接賦值使用

                      關聯數組必須先聲明以後才能賦值使用

                                    如:[root@centos7 ~]$array3[0]=mage

                                           [root@centos7 ~]$array3[1]=zhangsir

                                           [root@centos7 ~]$echo  ${array3[*]}

                                          mage  zhangsir

                                           [root@centos7 ~]$echo  ${array3[1]}

                                           zhangsir

                                           [root@centos7 ~]$echo  ${array3[0]}

                                           mage

                                           [root@centos7 ~]$array4[ceo]=mage

                                           [root@centos7 ~]$array4[cto]=zhangsir

                                           [root@centos7 ~]$echo  ${array4[*]}

                                           zhangsir

                                    直接賦值使用關聯數組會賦值失敗,只顯示最後一個值

                    

數組引用:

               引用數組元素:

                             ${array_name[index]}

                            注意:省略[index表示引用下標爲0的元素]

               引用數組全部元素

                            ${array_name[@]}

                            ${array_name[*]}

               數組的長度(數組中元素的個數)

                            ${#array_name[*]}

                            ${#array_name[@]}

               刪除數組中的某元素:致使稀疏格式

                            unset  array[index]

               刪除整個數組

                            unset  array

                             

數組數據處理

               引用數組中的元素:

                            數組切片:${array[@]:offset:number}

                                   offset:     要跳過的元素個數

                                    number:要取出的元素個數

                             ${array[0]:offset}            取偏移量以後的全部元素

                            ${array[0]: -n}              取最後n個元素

                            ${array[0]::2}                 取開頭2個元素

                            ${array[0]:  -m:-n}         跳過最後第n+1個到第m個元素間的全部元素

                             

               向數組中追加元素:

                            array[${#array[*]}]=

               

               關聯數組:

                            declare -A  array_name

                             array_name=([idx_name1]=val1 [idx_name2]=val2  ...)

                             

 

字符串處理-------------------------------------------------------------------------

 

字符串切片:

               ${#var}:                         返回字符串變量var的長度

               ${var:offset}:                  返回字符串變量var中從第off個字符後(不包括第offset個字符)的字符

                                                         開始,到最後的部分,offer的取值在0到${#var}-1之間(bash4.2以後容許爲負值)

               ${var:offset:number}:     返回字符串變量var中第off個以後的num個字符(不包含off)

               ${var: -n}:                            取字符串最右側那個字符(冒號後需加一個空格)

               ${var: -n:-m}:                取倒數第m+1個字符 到 倒數第n個字符

               

基於模式取子串:

               ${var#*word}        其中var爲變量名,不須要加$引用,word能夠是指定的任意字符串

                     功能:自左而右,查找var變量所存儲的字符串中,第一次出現的word,刪除字符串開頭

                     至第一次出現word字符之間的全部字符

               ${var##*word}

                      貪婪模式,刪除字符串開頭到最後一次」word「指定的字符之間的全部內容

                    

               ${var%word*}         其中word能夠是指定的任意字符串

                     功能:    自右邊而左,查找var變量所存儲的字符串中,第一次出現word,刪除字符串最後一個字符

                     向左至第一次出現word字符之間的全部字符

               ${var%%word*}        

                                    自右而左,刪除至最後一個word所指定的字符串

                                    

查找替換:

               ${var/pattern/substr}:

                            查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substr替換之

               ${var//pattern/substr}:

                            替換全部能被pattern所匹配到的字符串,以substr替換

               ${var/#pattern/substr}

                            行首被pattern匹配,並替換

               ${var/%pattern/substr}:

                            行尾被pattern匹配,並替換

               

查找刪除:

               ${var/pattern}:               刪除第一次被pattern匹配到的字符串

               ${var//pattern}:       刪除全部被pattern匹配到的字符串

               ${var/#pattern}:     刪除pattern爲行首所匹配到的字符串

               ${var/%pattern}:     刪除pattern爲行尾所匹配到的字符串

               

字符串大小寫轉換:

               ${var^^} 把var中全部的小寫字母轉換爲大寫

               ${var,,}    把var中全部的大寫字母轉換爲小寫

               

 

高級變量用法:-------------------------------------------------------------------

 

變量賦值:

               var=${str-expr}      str爲變量,expr爲字符串

                            若是str沒有沒配置,var=expr

                            若是str配置且爲空,var=

                            若是str配置且非空,var=$str

               var=${str:-expr}    

                            若是str沒有配置或者爲空,var=expr

                            若是str已配置且非空:      var=$str

               其餘諸多用法,此處不一一列舉,若有須要查看相關表格查詢

 

高級變量用法:有類型變量

               shell變量通常是無類型的,可是bash  shell提供了declare和一樣typeset兩個命令

               用於指定變量的類型,兩個命令是等價的

 

declare:

               declare [option] [var]

                            -r           聲明或顯示只讀變量

                            -i           整型數

                            -a          數組

                            -A          關聯數組

                            -f           顯示已定義的全部函數名及其內容

                            -F           僅顯示已定義的全部函數名

                            -x          聲明或顯示環境變量和函數

                            -xf 全局函數

                            -l           聲明變量爲小寫字母

                            -u          聲明變量爲大寫字母

               declare -ig   在函數中定義普通變量,centos6不支持           

eval:

               eval命令將會首先掃描命令進行全部的置換,而後再執行該命令。該命令適用於那些一次

               掃描沒法實現其功能的變量:該命令對變量進行兩次掃描

               示例:    eval  echo {1..$i}

                    

 

間接變量引用:

               若是第一個變量的值是第二個變量的名字,從第一個變量引用第二個變量的值

               就稱爲間接變量引用

               如:

                             var1=var2

                             var2=nnn

               bash 提供了兩種格式實現間接變量引用

                            eval  var=\$$var1

                            var3=${!var1}

                     如:      

                                    var1=var2

                                    var2=nnn

                                   var3=${!var1} 或者 eval var3=\$$var1

                                   echo  $var3

                                    nnn

                    

建立臨時文件:---------------------------------------------------------------------

mktemp :  

               建立並顯示臨時文件,可避免衝突

               mktemp [option]..[template]

                            template:       filenameXXX

                            -d          建立臨時目錄

                            -p DIR 或 --tmpdir=DIR     指明臨時文件所存放目錄位置

               示例:

                            tmpfile1=`mktemp  httptmp-XXX`

                            tmpdir=`mktemp -d  /tmp/roottmp-XXXX`

                            tmpdir=`mktemp  --tmpdir=/tmp roottmp-XXXX`

                             

 

安裝複製文件:

install       命令:

                     install [options] source  dest       單文件

                     install [] source dir                    單文件

                     install [] -t dir source           單文件

                     install [] -d  dir            建立空目錄

               選項:

                     -m mode 默認755

                     -o  owner

                     -g  group

               示例:

 

 

expect介紹-----------------------------------------------------------------------

               expect 是由Don Libes 基於Tcl(Tool Command Language)語言開發的

               主要應用於自動化交互式操做的場景,藉助expect處理交互的命令,能夠將交互過程

               如:ssh登陸,ftp登陸等寫在一個腳本上,使之自動化完成。尤爲適用於須要對多臺

               服務器執行相同操做的環境中,能夠大大提供系統管理人員的工做效率

 

expect命令:

               expect [選項] [-c cmds] [[ -f[f|b]] cmdfile ]  [args]

               選項:

                     -c          從命令行執行expect腳本,默認expect是交互地執行的

                            示例:expect -c 'expect "hello" { send "you said  hello\n" }'

                     -d          能夠輸出調試信息

                            示例:expect -d ssh.exp

               

               expect中的相關命令

                            spawn           啓動新的進程

                            send              用戶向進程發送字符串

                            expect            從進程接受字符串

                            interact   容許用戶交互

                            exp_continue 匹配多個字符串,在執行動做後加此命令

                             

               expect最經常使用的語法(tcl語言:模式-動做)

                             單一分支模式語法:

                                   expect "hi"  { send "you said hi \n"}

                                    匹配到hi後,會輸出"you said  hi",並換行

                            多分支模式語法:

                                   expect "hi"  { send "You said hi\n" } \

                                   "hehe" { send "Hehe yourself\n" } \

                                   "bye" { send "Good bye\n" }

                                     匹配hi,hello,bye任意字符串時,執行相應輸出。等同以下:

                                   expect  {

                                          "hi"  { send "You said hi\n"}

                                          "hehe"  { send "Hehe yourself\n"}

                                          "bye"  { send "Good bye\n"}

                                   }                                   

expect 示例:

        ssh自動鍵入密碼

                     #!/usr/bin/expect

                     spawn ssh  192.168.65.132

                     expect  {

                                   "yes/no"  { send "yes\n";exp_contunue }

                                   "password"  { send "112233\n"; }

                     }

                      interact

                     #expect  eof

               

        scp自動鍵入密碼

                     #!/usr/bin/expect

                     spawn scp /etc/passwd  192.168.65.132:/data

                     expect  {

                                   "yes/no"  { send "yes\n";exp_continue }

                                   "password"  {send "112233\n" }

                     }

                     expect eof                   

        

        自動從文件獲取ip地址,且登陸ip地址機器的root帳號,並建立帳號

        也能夠不用條用,直接在bash腳本中引用expect代碼

                     cat ssh.exp  

                            #!/usr/bin/expect

                            set ip [lindex $argv  0]

                            set user [lindex  $argv 1]

                            set password [lindex  $argv 2]

                            spawn ssh  $user@$ip

                            expect  {

                                           "yes/no" { send "yes\n";exp_continue  }

                                           "password" { send "$password\n"  }

                             }

                            expect "]#" { send "useradd user1\n" }

                            expect "]#" { send "echo nagedu |passwd --stdin  user1\n"}

                            send  "exit\n"

                             #interact

                            expect eof            

                    

                     cat   sshauto.sh

                            #!/bin/bash

                            while read ip;do

                             user=root

                             password=112233

                            ssh.exp $ip $user  $password

                            done <  /root/bin/ip.txt

 

        自動從文件獲取ip地址,並scp同一文件到全部主機的root目錄.txt 

                     #!/bin/bash

                     declare  password=112233

                     while read ip;do

                                   expect  <<EOF

                                   spawn scp  /root/bin/scpauto.sh $ip:/root

                                   expect  {

                                                  "password" { send "112233\n"  }

                                    }

                     expect  eof

                     EOF

                     done <  /root/bin/ip.txt

 

 

筆記整理完成時間:2018年5月16日20:21:12

相關文章
相關標籤/搜索