在 bash 中使用函式

roc_guo發表於2023-01-06

當你的 bash  中程式碼非常多的時候,會看起來很混亂,其中有部分程式碼有可能是重複的。這個時候,可以使用函式來避免重複的程式碼。

今天我們將介紹在 bash 中如何建立函式,以及函式中的返回值、傳遞引數等內容。

在 bash 中建立函式

建立 bash 函式有兩種不同的語法。最常用的方法如下:

function_name () {
    commands
}

第二種方法不太常用,如下所示:

function function_name {
    commands
}

在使用函式時,需要注意以下幾點:

  1. 除非被呼叫,否則函式永遠不會被執行;

  2. 函式必須先定義,然後才能被呼叫。

作為演示,我們建立一個 fun.sh  ,如下程式碼:

#!/bin/bash
hello () {
echo "Hello World"
}
hello
hello
hello

上述指令碼中,我們定義了一個名為 hello 的函式,它將在終端上列印 Hello World。後面我們呼叫了三次 hello 函式,因此,執行指令碼後,你會在螢幕上看到 Hello World 列印了三次:

$ ./fun.sh
Hello World
Hello World
Hello World
函式的返回值

在很多程式語言中,函式在呼叫時都會返回一個值,然而,在 bash 函式中沒有返回值。

當函式執行完成時,會返回一個 $? 變數作為退出狀態,0 表示成功執行,其他非零正整數(1 - 255)表示執行失敗。

我們來寫一個例子,命名為 error.sh,在其中寫一個 return 語句,如下程式碼所示:

#! /bin/bash
error () {
blabla
return 0
}
error
echo "The return status of the error function is: $?"

執行結果如下:

$ ./error.sh
./error.sh: line 4: blabla: command not found
The return status of the error function is: 0

因為有 return 0 這一行,所以即使函式中有 blabla 這一行的報錯,error 函式還是返回了一個執行成功的狀態碼 0。

return 語句執行後,函式會被立即終止。

向 bash 函式傳遞引數

我們可以向函式傳遞引數,就像向 bash 指令碼傳遞引數一樣。

作為演示,我們建立一個名為 iseven.sh 的指令碼,如下所示:

#!/bin/bash
iseven () {
    if [ $(($1 % 2)) -eq 0 ]; then
        echo "$1 is even."
    else
        echo "$1 is odd."
    fi
}
iseven 3
iseven 4
iseven 20
iseven 111

iseven() 函式判斷數字是偶數還是奇數。在呼叫的時候,將引數放在函式名後面,函式執行的時候會讀取 $1 來獲取傳遞的引數。我們來執行一下:

$ ./iseven.sh
3 is odd.
4 is even.
20 is even.
111 is odd.

這裡需要注意,bash 函式中的引數,和 bash 指令碼的引數需要區分開來,看如下 funarg.sh 指令碼:

#!/bin/bash
fun () {
echo "$1 is the first argument to fun()"
echo "$2 is the second argument to fun()"
}
echo "$1 is the first argument to the script."
echo "$2 is the second argument to the script."
fun Yes 7

執行結果如下:

$ ./funarg.sh Cool Stuff
Cool is the first argument to the script.
Stuff is the second argument to the script.
Yes is the first argument to fun()7 is the second argument to fun()

可以看到,同樣是使用 $1 和 $2 來引用指令碼引數和函式引數,當實際呼叫時,取值是不同的。

bash 函式中的全域性變數和區域性變數

與大多數程式語言累死,bash 變數具有全域性變數和區域性變數之分。其中全域性變數可以在任何位置方位到,而區域性變數只能在其定義的函式中訪問。

作為演示,看如下 scope.sh 指令碼:

#!/bin/bash
v1='A'
v2='B'
myfun() {
    local v1='C'
    v2='D'
    echo "Inside myfun(): v1: $v1, v2: $v2"
}
echo "Before calling myfun(): v1: $v1, v2: $v2"
myfun
echo "After calling myfun(): v1: $v1, v2: $v2"

我們首先定義了兩個全域性變數 v1 和 v2,然後在 函式 myfun() 中,使用 local 關鍵字 定義了一個區域性變數 v1,並修改了全域性變數 v2。在不同的函式中,區域性變數可以使用相同的變數名。

執行一下,結果如下:

$ ./scope.sh
Before calling myfun(): v1: A, v2: B
Inside myfun(): v1: C, v2: D
After calling myfun(): v1: A, v2: D

由此,我們可以看到:

  1. 如果區域性變數的變數名與全域性變數的變數名相同,那麼區域性變數優先順序會更高;

  2. 在函式中可以更改全域性變數的值。
遞迴函式

遞迴函式是一個呼叫自身的函式。階乘計算是遞迴函式的經典例子,看下面的指令碼 factorial.sh:

#!/bin/bash
factorial () {
    if [ $1 -le 1 ]; then
        echo 1
    else
        last=$(factorial $(( $1 -1)))
        echo $(( $1 * last ))
    fi
}
echo -n "4! is: "
factorial 4
echo -n "5! is: "
factorial 5
echo -n "6! is: "
factorial 6

任何遞迴函式都要從一個基本條件開始,這個基本條件必須可以結束遞迴函式呼叫鏈。在 factorial() 函式中,基本條件為:

if [ $1 -le 1 ]; then
    echo 1

然後匯出階乘函式的遞迴情況。要計算 n 的階乘,其中 n 是大於 1 的正數,可以將 n 乘以 n-1 的階乘:

factorial(n) = n * factorial(n-1)

使用上面那個公式來編寫遞迴函式的演算法:

last=$(factorial $(( $1 -1)))
    echo $(( $1 * last ))

然後執行一下,檢查執行結果:

$ ./factorial.sh
4! is: 24
5! is: 120
6! is: 720


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69901823/viewspace-2931103/,如需轉載,請註明出處,否則將追究法律責任。

相關文章