天天看點

Shell函數(函數定義、函數變量、函數調用、函數傳參、函數傳回值、擷取函數傳回值)

分享知識 傳遞快樂

1、函數定義

linux shell 可以使用者定義函數,然後在shell腳本中可以随便調用。Shell 函數定義的文法格式如下:

[function] funname [()]{
    函數體
    [return int;]
}      

格式1:

簡化寫法,不寫 function 關鍵字:

函數名(){
    函數體
}      

格式2:

這是标準寫法,也推薦大家使用的寫法:

function 函數名(){
  指令序列
}      

這樣友善做到一看就懂。

格式3:

如果寫了 function 關鍵字,也可以省略函數名後面的小括号:

function 函數名{
  指令序列
}      

說明:

  • function 是 Shell 中的關鍵字,專門用來定義函數;可以帶function funname () 定義,也可以直接funname () 定義,不帶任何參數;
  • funname 是函數名;
  • 函數體 是函數要執行的代碼,也就是一組語句;
  • return int 表示函數的傳回值,其中 return 是 Shell 關鍵字,專門用在函數中傳回一個值;這一部分可以寫也可以不寫,如果不加,将以最後一條指令運作結果,作為傳回值。

2、函數變量

Shell 函數的變量不像其它語言中需要在變量前定義變量類型什麼的,更沒有結果符号等。文法:

num=1      

變量作用域

局部變量:作用域是函數的生命周期;在函數結束時被自動銷毀。定義局部變量的方法:

local VAR=VALUE      

本地變量:作用域是運作腳本的shell程序的生命周期;是以,其作用範圍為目前shell

示例一:

#!/bin/bash

#在函數外定義本地變量
var="Hello,World"

function show() {
    #在函數内改變變量内容
    var="Hi,var is changed"
}
echo "$var"
show
echo "$var"      

輸出結果:

[guest@localhost shell]$ ./tempsh.sh
Hello,World
Hi,var is changed      

結果顯示在調用函數後,原有的本地變量var被替換了。還好這個變量并不是重要的部分,想想若是PATH被替換了,那麼這個函數的罪過就大了。是以我們如何即調用函數中定義的變量同時又不對本地變量造成任何影響呢?局部變量的出現就是為了解決這個問題。

下面看看在使用了局部變量後的效果。

#!/bin/bash
#在函數外定義本地變量
var="Hello,World"

function show() {
    #在函數内改變變量内容
    local var="Hi,var is changed"
    echo "$var"
}
echo "$var"
show
echo "$var"      

輸出結果

[guest@localhost shell]$ ./tempsh.sh
Hello,World
Hi,var is changed
Hello,World      

該實驗結果說明,使用局部變量後,函數體中出現的變量作用範圍隻存在于目前函數生命周期。

3、函數調用

定義函數的代碼段不會自動執行,而是在調用時執行;在函數定義好後,使用者可以在shell 中直接調用,調用時不用帶上();調用 Shell 函數時可以給它傳遞參數,也可以不傳遞。如果不傳遞參數,直接給出函數名字即可。

示例一:

#!/bin/bash

# 函數定義
function show(){
    echo "Hello word"
}

# 函數調用
show      

輸出結果:

Hello word      

函數調用成功。上邊的例子是把函數把在腳本上邊,那麼如果放函數放在下邊會怎樣呢?

無非就兩種結果:1成功,2失敗

下面我們舉例測試一下:

示例二:

#!/bin/bash

# 函數調用
show

#函數定義
function show(){
    echo "Hello word"
}      

輸出結果:

./tempsh.sh:行4: show: 未找到指令      

系統報錯,為啥?為什麼會報錯呢?

首先,腳本的執行順序是從上到下順序執行的,是以會先執行show,通過定義的環境變量$PATH定義的路徑找不到show對應的指令是以報“show:未找到指令”。

我們在終端指令行中輸錯指令報錯也是這個原因。終端指令行預設會将最左面輸入的内容當做指令,是以若是錯誤的指令,不是指令的指令等内容都會報錯。

通過上面的對比,我們至少知道函數的調用若是在同一個腳本中,調用操作需要在定義的函數後面。

4、函數傳參

函數傳參調用文法:

函數名 參數1 參數2 ....      

如果傳遞參數,那麼多個參數之間以空格分隔:

funname param1 param2 param3      

不管是哪種形式,函數名字後面都不需要帶括号。和其它程式設計語言不同的是,Shell 函數在定義時不能指明參數,但是在調用時卻可以傳遞參數,并且給它傳遞什麼參數它就接收什麼參數。

在Shell中,調用函數時可以向其傳遞參數。在函數體内部,函數中的變量均為全局變量,沒有局部變量,若使用局部變量需要在變量前加上 local,通過 $n 的形式來擷取參數的值,例如,$1表示第一個參數,$2表示第二個參數....

示例:

#!/bin/bash

function show(){
    echo "第一個參數為 $1 !"
    echo "第二個參數為 $2 !"
    echo "第十個參數為 $10 !"
    echo "第十個參數為 ${10} !"
    echo "第十一個參數為 ${11} !"
    echo "參數總數有 $# 個!"
    echo "作為一個字元串輸出所有參數 $* !"
}

show 0 1 2 3 4 5 6 7 8 9 10 11      

輸出結果:

第一個參數為 0 
第二個參數為 1 
第十個參數為 10 
第十個參數為 9 
第十一個參數為 10 
參數總數有 12 個
作為一個字元串輸出所有參數 0 1 2 3 4 5 6 7 8 9 10 11      

注意:$10 不能擷取第十個參數,擷取第十個參數需要${10}。當n>=10時,需要使用${n}來擷取參數。

另外,還有幾個特殊字元用來處理參數:

參數處理 說明
$# 傳遞到腳本的參數個數
$* 以一個單字元串顯示所有向腳本傳遞的參數
$$ 腳本運作的目前程序ID号
$! 背景運作的最後一個程序的ID号
$@ 與$*相同,但是使用時加引号,并在引号中傳回每個參數。
$- 顯示Shell使用的目前選項,與set指令功能相同。
$? 顯示最後指令的退出狀态。0表示沒有錯誤,其他任何值表明有錯誤。

5、函數傳回值

退出狀态碼

在介紹函數傳回值前先了解一下跟函數傳回值有關的狀态退出碼。

Shell 中運作的每個指令都使用退出狀态碼(exit status)來告訴shell它完成了處理。退出狀态碼是一個0-255之間的整數值,在指令結束運作時由指令傳給shell。你可以捕獲這個值并在腳本中使用。

如何檢視退出狀态碼呢?

Linux提供了 $? 專屬變量來儲存上個執行的指令的退出狀态碼。你必須在你要檢視的指令之後馬上檢視或使用 $? 變量。它的值會變成Shell中執行的最後一條指令的退出狀态碼。

退出狀态碼大體分兩種:

  • 一種是指令正确執行的狀态碼,該狀态碼為:0
  • 一種是指令錯誤執行的狀态碼,為1-255

 Linux退出狀态碼

狀态碼 描述
指令成功結束
1 通用未知錯誤
2 誤用shell指令
126 指令不可執行
127 沒找到指令
128 無效退出參數
128+x Linux信号x的嚴重錯誤
130 指令通過Ctrl+C終止
255 退出狀态碼越界

在腳本中也可以指定退出狀态碼的值,通過指令exit實作。

狀态碼取值範圍為0-255,如果在指定的狀态碼大于255,那麼shell會通過模(模就是256)運算得到相應的退出狀态碼。

示例一:

成功的

#!/bin/bash

# 函數定義
function show(){
    echo $(date +%Y%m%d)
}
show
echo $?      

輸出結果:

示例二:

失敗的

#!/bin/bash

SYS_DATE=$(date +%Y%m%d)

echo $SYS_DATE

# 函數定義
function show(){
    log=`lt`
    echo log
}
show
echo $?      

輸出結果:

[guest@localhost shell]$ ./tempsh.sh 
20191123
./tempsh.sh:行10: lt: 未找到指令
log
0      

這次,由于函數最後一行指令正确執行,函數的退出狀态碼就是0,盡管函數中有一條指令沒有成功運作。

使用函數的預設退出狀态碼是很危險的,幸運的是return指令可以解決這個問題。

示例:

#!/bin/bash

SYS_DATE=$(date +%Y%m%d)

echo $SYS_DATE

# 函數定義
function show(){
    log=`lt`
    echo log
    return 2
}
show
echo $?      

輸出結果:

[guest@localhost shell]$ ./tempsh.sh 
20191123
./tempsh.sh:行10: lt: 未找到指令

2      

還是使用相同的函數,在函數最後加上return指定的狀态碼2。

函數傳回值

Shell函數傳回值,常用的兩種方式:return、echo。

1)return 語句

Shell函數的傳回值,可以和其他語言的傳回值一樣,通過return語句傳回,return隻能用來傳回整數值。

示例一:

#!/bin/bash

function getResultFun(){
    echo "這是我的第一個 shell 函數!"
    return `expr 1 + 1`
}

getResultFun
echo $?      

輸出結果:

這是我的第一個 shell 函數!
2      

Shell 函數傳回值隻能是整形數值,一般是用來表示函數執行成功與否的,0表示成功,其他值表示失敗。用函數傳回值來傳回函數執行結果是不合适的。如果return某個計算結果,比如一個字元串,往往會得到錯誤提示:“numeric argument required”。

如果一定要讓函數傳回一個或多個值,可以定義全局變量,函數将計算結果賦給全局變量,然後腳本中其他地方通過通路全局變量,就可以獲得那個函數“傳回”的一個或多個執行結果了。

示例:

#!/bin/sh

function getStr(){
  return "string"
}

getStr
echo $?      

輸出如下:

./test.sh: line 5: return: string: numeric argument required
255      

可以看到已經提示要求return 整數類型,真實傳回值是255。當面對這種問題怎麼解決呢?

别急,斷續看下去你就會找到你想要的答案了。

2)echo 語句

echo是通過輸出到标準輸出傳回,可以傳回任何類型的資料。

示例:

#!/bin/sh

function test()  {
  echo "arg1 = $1"
  if [ $1 = "1" ] ;then
    echo "1"
  else
    echo "0"
  fi
}

echo
echo "test 1"
test 1

echo
echo "test 0"
test 0

echo
echo "test 2"
test 2      

輸出結果:

test 1
arg1 = 1
1

test 0
arg1 = 0
0

test 2
arg1 = 2
0      

3)函數傳回值總結

學習了上面的函數傳回值的操作後我們下面做個知識總結,我們先看一用例:

#!/bin/bash

function getResultFun(){
    echo "這是我的第一個 shell 函數!"
    return `expr 1 + 1`
}

getResultFun
echo $?

function getResultFun2(){
 echo "這是我的第二個 shell 函數!"
 expr 1 + 1
}

getResultFun2
echo $?

getResultFun
echo 在這裡插入指令!
echo $?      

輸出結果:

這是我的第一個 shell 函數!
2
這是我的第二個 shell 函數!
2
0
這是我的第一個 shell 函數!
在這裡插入指令!
0      

這是為什麼?

因為調用 getResultFun2 後,函數最後一條指令 expr 1 + 1 得到的傳回值($?值)為 0,意思是這個指令沒有出錯。所有的指令的傳回值僅表示其是否出錯,而不會有其他有含義的結果。

第二次調用 getResultFun 後,沒有立即檢視 $? 的值,而是先插入了一條别的 echo 指令,最後再檢視 $? 的值得到的是 0,也就是上一條 echo 指令的結果,而 getResultFun 的傳回值被覆寫了。下面這個測試,連續使用兩次 echo $?,得到的結果不同,更為直覺:

#!/bin/bash

function getResult(){
    echo "這是我的第一個 shell 函數!"
    return `expr 1 + 1`
}

getResult
echo $?
echo $?      

輸出結果:

這是我的第一個 shell 函數!
2
0      

6、擷取函數傳回值

我們上面談到了函數定義、傳參、調用、傳回結果,那我們如果得到傳回結果呢?上面也談到了一種擷取傳回結果的方法 $? ,難道隻有這一種方式嗎?答案肯定不止。

示例一:

用 $? 擷取傳回值,上面已有介紹,在這裡就不做介紹了。

示例二:

#!/bin/sh

function getStr(){
  return "string"
}

#方法一
echo `getStr` 

#方法二
echo $(getStr)      

兩種寫法的原理一樣的,将getStr當成指令執行,然後擷取其标準輸出。

示例三:函數傳參

#!/bin/bash

#建立目錄
function createDir(){
  if [ ! -d $1 ]; then
    mkdir -p $1
  fi
}

DIR="temp/"
# 兩者二先一
#$(createDir $DIR)
$(createDir "temp/")      

函數傳回值擷取的方法總結:

  • 用變量接收函數傳回值,函數用echo等标準輸出将要傳回的東西列印出來。
  • 用 $? 來接收函數的執行狀态,但是 $? 要緊跟在函數調用處的後面。
上一篇: 猜算式

繼續閱讀