bash腳本編程進階篇

  bash腳本編程進階篇

  函數、數組、字符串操作


    一.函數:腳本編程中的函數與我們數學中的函數有着根本區別。這裏的函數主要是爲了實現過程式編程代碼重用的作用。比如一個用於計算數字的函數,當我們需要使用計算數字的時候,直接調用這個函數過來而不必每一次計算數字都要自己重新寫一次。因此,函數的主要功能可以概括爲:便於實現模塊化編程;便於代碼的重用;使程序簡潔。我們定義函數,可以分兩種兩種結構。 第一種函數結構,用function聲明一個函數,後跟函數名。函數體用花括號括起來。第二種結構是用函數名跟小括號(),依然是把函數體寫在花括號中,兩種任選其一。

function f_name {
函數體
}

或者
f_name() {
函數體
}

    瞭解了函數的結構,看一下我們具體如何使用函數。函數本身是爲了實現某種功能的功能模塊。因此在寫函數體時,只要能完整實現特定功能;且能滿足多方調用即可。我這裏給個例子比如:我們要用函數實現如下功能,腳本運行時輸出一段提示,要求用戶給個用戶名。如果用戶不給用戶名,錯誤提示返回值爲1,如果給了一個錯誤的用戶名,也給出錯誤提示。繼續讓用戶出入用戶名。如果用戶給予一個用戶名正確,就輸出該用戶的shell類型,用戶輸入quit可以實現退出。

#!/bin/bash
#
showuserinfo() {
    [ $# -lt 1 ] && return 1
    ! id $1 &> /dev/null && return 2
    grep "^$1\>" /etc/passwd | cut -d: -f7
    [ $? -eq 0 ] && return 0 || return 3
}
while true; do
    read -p "Enter a username: " username
    [ "$username" == 'quit' ] && break
    showuserinfo $username
    [ $? -ne 0 ] && echo "There is something wrong."
done

    這裏詳細分析一下這個例子:1.函數中出現了return 1,3之類,這些其實是函數的返回值。他反應的是函數的執行結果。另外函數也有退出狀態碼,函數的退出狀態碼與腳本的退出狀態碼是相同的選取方法。都是取各自最後一個語句的執行狀態結果(注意是執行狀態結果)。我們也可以自定義。形如我們相面的例子所寫return #.這裏#要求在[0-255]之間。函數體在執行過程中,一旦遇到return就會停止運行。2.我們這裏用於顯示用戶shell類型的的函數,用戶名是由腳本執行時交互式輸入的。很顯然函數也是可以實現傳遞參數的。$1,$#,$*等變量要熟練掌握哦。3.這裏函數的調用看到案例,就是直接使用函數名即可實現調用。

    注意:我們在函數中使用變量時,要注意聲明本地變量。local VAR=VALUE ,不然在函數體中如果函數變化,會引起其他同名函數的數值變化。

    函數的遞歸調用,遞歸調用實際就是函數自身調用自身。這麼說起好像有點抽象。想象一下數學裏的階乘表達式。10! n(n-1)! n(n-1)(n-2)! ... 這表達式就是最典型的遞歸。我們下面來看一下,如何用函數的遞歸調用來實現。

fact() {
if [ $1 -eq 0 -o $1 -eq 1 ]; then
echo 1
else
   echo $[$1*$(fact $[$1-1])]
fi
}

    注意:函數的遞歸調用對於計算機而言是運算效率是相當低的,因爲他是把所有的運行結果先存儲在內存中,直到運行到最後一個表達式,再從頭輸出數據。

    函數的數組:函數的數組可以理解是連續多個的獨立內存空間,每個內存空間其實就相當於一個比變量。這些所謂的比變量我們稱之爲函數的數組元素。

    二.數組元素的組成:數組名+索引號的(索引號是從零編號的)例如:ARRAY[0]="hello" 這裏的數組名就是ARRAY,[0]即表示索引號。

    數組的用法:首先要先聲明一個數組,declare -a ARRAR_NAME。這是很關鍵不可省略的,因爲如果不聲明。因爲如果不聲明,函數就會把這裏當做一個變量來處理了。數組既然是一個連續的空間存儲單元,他就需要賦值。數組的賦值方式多種:

(1) 一次只賦值一個元素
ARRAY[index]=VALUE
a[0]="abc"
(2) 一次賦值全部元素
ARRAY=("mon" "tue" "wed")
(3) 指定索引進行賦值
ARRAY=([0]="sun" [1]="mon" [5]="fri")
(4) read -a ARRAY

        賦值實現之後,那麼即正常調用了。引用數組元素,${數組元素}=${arrsy[0]}。這是對數組中具體某個數組元素的調用。數組的長度我們是使用:${#ARRAY[*]}或者來實現的。來個例子:定義一個數組,數組元素爲/var/log目錄下,所有以.log結尾的文件的名字;而後顯示其索引爲奇數的元素的內容;

#!/bin/bash
#
declare -a files
files=(/var/log/*.log)
for i in `seq 0 $[${#files[*]}-1]`; do
    [ $[$i%2] -ne 0 ] && echo "$i: ${files[$i]}"
done

    數組的元素的相關處理問題:

        1.挑選一個與元素:${ARRAY[i]} 

        2.挑選某幾個連續的元素:${ARRAY[@]:offset:number}  這裏offset指從數組開始偏移的第幾個數,number指的是從索引號開始取的個數。

        3.挑選某元素開始到最後的所有元素:${ARRAY[@]:offset} 這就表示從指定索引號開始之後的所有元素都取出。

        4.使用所有元素:${ARRAY[@]}

        5.從數組中追加一個元素: ARRAY[${#ARRAY[@]}]

        6.從數組中刪除一個元素: unset ARRAY[i]    

    關聯數組:關聯數組與數組的不同有聲明時爲-A;而且可以自定義任意字符串當作索引比如:

declare -A week

week=([mon]="Monday" [tue]="Tuesday")此時索引不再是數字了。

    三.字符串操作:

    我們知道對於文本而言可以使用諸多相sed等工具找出自己想要的行或者一個單詞。這種方式非常方便,於是對於字符串我們也有相似的處理方式。

    字符串的切片:

字符串切片格式:${var:offset:lenth} 這裏格式很像數組的選取,只是此處的var不是數組而是代表一個變量比如:a="hello,world", ${a:5:2} 結果爲:,w 。

    取字符串最後的幾個字符:${var: -lenth} 例如:a="hello,world", ${a: -2} 結果就是ld。注意:冒號之後有空格;

    基於模式取字符串:

    1.${var#*word}:其中word可以是指定的任意自己想要查找的字符。含義:自左而右,刪除到查找var變量所存儲字符中,第一次出現的word的地方。例如:

# mypath='sysconfig/network-scripts/ifcfg-eth0'
# echo ${mypath#*/}
network-scripts/ifcfg-eth0

    2.${var##*word}: 其中word可以是指定的任意字符;含義:自左而右,刪除var變量所存儲字符中,直到最後一次出現的word。

# mypath='/sysconfig/network-scripts/ifcfg-eth0'
# echo ${mypath##*/}
ifcfg-eth0    
          

    3.${var%word*}: 自右而左,刪除第一次word出現處的字符開始直到尾部的所有字符;

     

# mypath='/sysconfig/network-scripts/ifcfg-eth0'
# echo ${mypath%/*}
/sysconfig/network-scripts
          

    4.${var%%word*}:自右而左,刪除最後一次word出現處的字符開始直到尾部的所有字符;

理解記憶:這裏可以這麼記憶,#表示從左至右,所以*要放在word左邊表示要刪除的部分,1個#就表示第一次匹配到的地方,##就表示最後一次匹配到的地方。%表示從右向左,所以*要放在word右邊表示要被刪除的部分,同樣的第一個%表示第一次被匹配到的地方,%%表示最後一次被匹配到的地方。

    查找並替換:

    ${var/pattern/substi}:查找var所表示的字串中,第一次被Pattern匹配到的字串,並以substi替換之;

    例如:

# mypath='/sysconfig/network-scripts/ifcfg-eth0'
# echo ${mypath/\/sysconfig/etc}
 etc/network-scripts

    ${var//patten/substi}:查找var所表示的字串中,所有被Pattern匹配到的字串,並以substi替換之;

    

    ${var/#pattern/substi}:以行首錨定的方式將pattern匹配至var所表示的字串上,如果能匹配,則以substi替換之;

    

# mypath='/sysconfig/network-scripts/ifcfg-eth0'
# echo ${mypath/#\/sysconfig/etc}
 etc/network-scripts

    ${var/%pattern/substi}:以行尾錨定的方式將pattern匹配至var所表示的字串上,如果能匹配,則以substi替換之;

    這裏的模式可使用?, *元字符;

    查找並刪除:

    ${var/pattern}:刪除pattern匹配到的第一次出現;

    ${var//pattern}: 刪除pattern匹配到的所有出現;

    ${var/#pattern}:刪除pattern匹配到在行首的地方

    ${var/%pattern}:刪除pattern匹配到在行尾的地方

    這裏可以和上一個替換加在一起記憶,理解爲替換爲空,那麼就是刪除了。

    字符串大小寫轉換:

    ${var^^}:小寫-->大寫    

 mypath='/sysconfig/network-scripts/ifcfg-eth0'
     echo ${mypath^^}
    /SYSCONFIG/NETWORK-SCRIPTS/IFCFG-ETH0

 

    ${var,,}:大寫-->小寫    

    變量賦值:

    ${var:-word}: 如果var爲空或未設置,那麼返回word;否則,則返回var中的值;

    ${var:=word}:如果var爲空或未設置,那麼返回word,並且將word賦值給var;否則,返回var中的值;

    ${var:?err_info}:如果var爲空或未設置,那麼返回錯誤信息;否則,則返回var自身的值;

    ${var:+word}:如果var自身有正常數據,則返回word;




























發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章