Linux命令行與Shell腳本編程
六.函數(shù)
- 腳本函數(shù)基礎(chǔ)
- 函數(shù)返回值
- 在函數(shù)中使用變量
- 數(shù)組變量和函數(shù)
- 函數(shù)遞歸
- 創(chuàng)建庫
- 在命令行中使用函數(shù)
可以將shell腳本代碼放入函數(shù)中封裝起來,這樣就能在腳本的任意位置多次使用.
6.1.腳本函數(shù)基礎(chǔ)
函數(shù)是一個(gè)腳本代碼塊,可以并在腳本中的任何位置重用它。當(dāng)需要在腳本中使用該代碼塊時(shí),直接通過函數(shù)名調(diào)用.
6.1.1.創(chuàng)建函數(shù)
bash shell腳本中創(chuàng)建函數(shù)的語法有兩種。
- 使用關(guān)鍵字function
function name {//函數(shù)的唯一名稱。腳本中的函數(shù)名不能重復(fù)
commands //組成函數(shù)的一個(gè)或多個(gè)bash shell命令。
}
- 近其他編程語言中定義函數(shù)的方式
name() {//函數(shù)名后的空括號(hào)表明正在定義的是一個(gè)函數(shù)
commands
}
6.1.2.使用函數(shù)
使用函數(shù)名調(diào)用函數(shù)
$ cat test1
#!/bin/bash
# using a function in a script
function func {
echo "This is an example of a function"
}
count=1
while [ $count -le 5 ]
do
func
count=$[ $count + 1 ]
done
$ ./test1
This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
- 函數(shù)定義不一定非要放在shell腳本的最開始部分,但必須定義在調(diào)用之后,在函數(shù)被定義之前調(diào)用,則會(huì)收到一條錯(cuò)誤消息.
func: command not found
- 如果定義了同名函數(shù),新定義就會(huì)覆蓋函數(shù)原先的定義,而不會(huì)有任何錯(cuò)誤消息.
6.2.函數(shù)返回值
bash shell把函數(shù)視為一個(gè)小型腳本,運(yùn)行結(jié)束時(shí)會(huì)返回一個(gè)退出狀態(tài)碼.
有3種方法能為函數(shù)生成退出狀態(tài)碼。
6.2.1.默認(rèn)的退出狀態(tài)碼
函數(shù)的退出狀態(tài)碼是函數(shù)中最后一個(gè)命令返回的退出狀態(tài)碼。函數(shù)執(zhí)行結(jié)束后,可以使用標(biāo)準(zhǔn)變量 $? 來確定函數(shù)的退出狀態(tài)碼.
- 函數(shù)執(zhí)行一結(jié)束就立刻讀取返回值。用$?變量提取函數(shù)返回值之前執(zhí)行了其他命令,函數(shù)的返回值會(huì)丟失。
#!/bin/bash
func1() {
## 命令執(zhí)行失敗
ls -l badfile
}
echo "testing the function: "
func1
echo "The exit status is: $?"
testing the function:
trying to display a non-existent file
ls: badfile: No such file or directory
The exit status is: 1
退出狀態(tài)碼是1,因?yàn)楹瘮?shù)中的最后一個(gè)命令執(zhí)行失敗.使用函數(shù)的默認(rèn)退出狀態(tài)碼是一種危險(xiǎn)的做法.
ps: 函數(shù)最執(zhí)行成功退出狀態(tài)碼為0.
6.2.2.使用return命令
bash shell會(huì)使用return命令以特定的退出狀態(tài)碼退出函數(shù)。return命令允許指定一個(gè)整數(shù)值作為函數(shù)的退出狀態(tài)碼.
$ cat test5
#!/bin/bash
# using the return command in a function
function dbl {
read -p "Enter a value: " value
echo "doubling the value"
return $[ $value * 2 ]
}
dbl
echo "The new value is $?"
$
$ ./test5
Enter a value: 200
doubling the value
The new value is 1
$
大于255的任何數(shù)值都會(huì)產(chǎn)生錯(cuò)誤的值.
6.2.3.使用函數(shù)輸出
需要返回較大的整數(shù)值或字符串,可以將函數(shù)的’輸出’保存到shell變量中.
result=$(function_name)
$ cat test5b
#!/bin/bash
# using the echo to return a value
function dbl {
read -p "Enter a value: " value
echo $[ $value * 2 ]
}
result=$(dbl)
echo "The new value is $result"
$
$ ./test5b
Enter a value: 200
The new value is 400
$
$ ./test5b
Enter a value: 1000
The new value is 2000
$
函數(shù)會(huì)用echo語句來顯示計(jì)算結(jié)果。腳本會(huì)獲取dbl函數(shù)的輸出,而不是查看退出狀態(tài)碼。
dbl函數(shù)實(shí)際上輸出了兩條消息。read命令輸出了一條簡短的消息來向用戶詢問輸入值。
bash shell并不將其作為STDOUT輸出的一部分,而是直接忽略。
如果用echo語句生成這條消息("Enter a value: ")來詢問用戶,消息就會(huì)與輸出值一起被讀入shell變量。
借助返回值方法,還可以返回浮點(diǎn)值和字符串.
6.3.函數(shù)中使用變量
在函數(shù)中使用變量時(shí),需要注意變量的定義方式和處理方式。
6.3.1.向函數(shù)傳遞參數(shù)
bash shell會(huì)將函數(shù)當(dāng)作腳本來對(duì)待。可以像普通腳本那樣向函數(shù)傳遞參數(shù).
函數(shù)名保存在$0變量中,函數(shù)參數(shù)依次保存在$1、
2
等變量中
.
可以用特殊變量
2等變量中.可以用特殊變量
2等變量中.可以用特殊變量#來確定傳給函數(shù)的參數(shù)數(shù)量.
(處理用戶輸入章節(jié))
腳本中調(diào)用函數(shù)時(shí),必須將參數(shù)和函數(shù)名放在同一行.然后用位置變量來獲取參數(shù)值。
func_name $value1 10
示例:
$ cat test6
#!/bin/bash
function addem {
if [ $# -eq 0 ] || [ $# -gt 2 ]
then
echo -1
elif [ $# -eq 1 ]
then
echo $[ $1 + $1 ]
else
echo $[ $1 + $2 ]
fi
}
echo -n "Adding 10 and 15: "
value=$(addem 10 15)
echo $value
echo -n "Let's try adding just one number: "
value=$(addem 10)
echo $value
echo -n "Now try adding no numbers: "
value=$(addem)
echo $value
echo -n "Finally, try adding three numbers: "
value=$(addem 10 15 20)
echo $value
$
$ ./test6
Adding 10 and 15: 25
Let's try adding just one number: 20
Now try adding no numbers: -1
Finally, try adding three numbers: -1
函數(shù)使用位置變量訪問函數(shù)參數(shù),無法直接獲取腳本的命令行參數(shù)。
$ cat badtest1
#!/bin/bash
# trying to access script parameters inside a function
function badfunc1 {
echo $[ $1 * $2 ]
}
if [ $# -eq 2 ]
then
value=$(badfunc1)
echo "The result is $value"
else
echo "Usage: badtest1 a b"
fi
$
$ ./badtest1
Usage: badtest1 a b
$ ./badtest1 10 15
./badtest1: * : syntax error: operand expected (error token is "*")
The result is
$
盡管函數(shù)使用了$1變量和$2變量,但和腳本主體中的$1變量和$2變量不同。
要在函數(shù)中使用腳本的命令行參數(shù),必須在調(diào)用函數(shù)時(shí)手動(dòng)將其傳入.
value=$(badfunc1 $1 $2)
在將$1和$2傳給函數(shù)后就能跟其他變量一樣供函數(shù)使用。
6.3.2.在函數(shù)中處理變量
變量的作用域是比較麻煩的.作用域是變量的有效區(qū)域.
函數(shù)有兩種類型的變量:
- 全局變量
- 局部變量
全局變量
在shell腳本內(nèi)任何地方都有效的變量。
在默認(rèn)情況下,在腳本中定義的任何變量都是全局變量。在函數(shù)外定義的變量可在函數(shù)內(nèi)正常訪問.
$ cat test8
#!/bin/bash
function dbl {
value=$[ $value * 2 ]
}
read -p "Enter a value: " value
dbl
echo "The new value is: $value"
$
$ ./test8
Enter a value: 450
The new value is: 900
$value變量在函數(shù)外定義并被賦值。如果變量在函數(shù)內(nèi)被賦予了新值,那么在腳本中引用該變量時(shí),新值仍可用。
局部變量
在任何在函數(shù)內(nèi)部使用的變量都可以被聲明為局部變量.local關(guān)鍵字保證了變量僅在該函數(shù)中有效。
- 在變量聲明之前加上local關(guān)鍵字.
- 在變量賦值語句中使用local關(guān)鍵字.
local temp
local temp=$[ $value + 5 ]
如果函數(shù)之外有同名變量,兩個(gè)變量的值互不干擾。
function func1 {
local temp=$[ $value + 5 ]
result=$[ $temp * 2 ]
}
6.4.數(shù)組變量和函數(shù)
在函數(shù)中使用數(shù)組變量.
6.4.1.向函數(shù)中傳遞數(shù)組
將數(shù)組變量當(dāng)作單個(gè)參數(shù)傳遞不起作用.
數(shù)組變量作為函數(shù)參數(shù)進(jìn)行傳遞,則函數(shù)只會(huì)提取數(shù)組變量的第一個(gè)元素。
$ cat badtest3
#!/bin/bash
function testit {
echo "The parameters are: $@"
thisarray=$1
echo "The received array is ${thisarray[*]}"
}
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
testit $myarray
$
$ ./badtest3
The original array is: 1 2 3 4 5
The parameters are: 1
The received array is 1
必須先將數(shù)組變量拆解成多個(gè)數(shù)組元素,然后將這些數(shù)組元素作為函數(shù)參數(shù)傳遞。最后在函數(shù)內(nèi)部,將所有的參數(shù)重新組合成一個(gè)新的數(shù)組變量。
$ cat test11
#!/bin/bash
function addarray {
local sum=0
local newarray
newarray=(`echo "$@"`)
for value in ${newarray[*]}
do
sum=$[ $sum + $value ]
done
echo $sum
}
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
arg1=$(echo ${myarray[*]})
result=$(addarray $arg1)
echo "The result is $result"
$
$ ./test11
The original array is: 1 2 3 4 5
The result is 15
6.4.2.從函數(shù)返回?cái)?shù)組
函數(shù)向shell腳本返回?cái)?shù)組變量先用echo語句按正確順序輸出數(shù)組的各個(gè)元素,腳本再將數(shù)組元素重組成一個(gè)新的數(shù)組變量.
$ cat test12
#!/bin/bash
function arraydblr {
local origarray
local newarray
local elements
local i
origarray=($(echo "$@"))
newarray=($(echo "$@"))
elements=$[ $# - 1 ]
for (( i = 0; i <= $elements; i++ ))
{
newarray[$i]=$[ ${origarray[$i]} * 2 ]
}
echo ${newarray[*]}
}
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
arg1=$(echo ${myarray[*]})
result=($(arraydblr $arg1))
echo "The new array is: ${result[*]}"
$
$ ./test12
The original array is: 1 2 3 4 5
The new array is: 2 4 6 8 10
通過$arg1變量將數(shù)組元素作為參數(shù)傳給arraydblr函數(shù)。
arraydblr函數(shù)將傳入的參數(shù)重組成新的數(shù)組變量,生成數(shù)組變量的副本。對(duì)數(shù)據(jù)元素進(jìn)行操作,并將結(jié)果存入函數(shù)中的數(shù)組變量副本。
6.5.函數(shù)遞歸
函數(shù)可以遞歸地調(diào)用.
遞歸函數(shù)通常有一個(gè)最終可以迭代到的基準(zhǔn)值。
遞歸算法的經(jīng)典例子是計(jì)算階乘:
$ cat test13
#!/bin/bash
function factorial {
if [ $1 -eq 1 ]
then
echo 1
else
local temp=$[ $1 - 1 ]
local result=$(factorial $temp)
echo $[ $result * $1 ]
fi
}
read -p "Enter value: " value
result=$(factorial $value)
echo "The factorial of $value is: $result"
$
$ ./test13
Enter value: 5
The factorial of 5 is: 120
6.6.創(chuàng)建庫
使用函數(shù)可以為腳本省去一些重復(fù)性的輸入工作.如果要在多個(gè)腳本中使用同一段代碼,通過庫解決.
bash shell允許創(chuàng)建函數(shù)庫文件,然后在多個(gè)腳本中引用此庫文件。
- 創(chuàng)建一個(gè)包含腳本中所需函數(shù)的公用庫文件。
$ cat myfuncs function addem { echo $[ $1 + $2 ] } function multem { echo $[ $1 * $2 ] }
- 在需要用到這些函數(shù)的腳本文件中包含myfuncs庫文件.
shell函數(shù)的作用域和環(huán)境變量一樣,shell函數(shù)僅在定義它的shell會(huì)話內(nèi)有效。
如果在shell命令行界面運(yùn)行myfuncs腳本,那么shell會(huì)創(chuàng)建一個(gè)新的shell并在其中運(yùn)行這個(gè)腳本。
這種情況下,函數(shù)會(huì)定義在新shell中,當(dāng)運(yùn)行另一個(gè)要用到這些函數(shù)的腳本時(shí),它們是無法使用的。
如果嘗試像普通腳本文件那樣運(yùn)行庫文件,函數(shù)也不會(huì)出現(xiàn)在腳本中.
使用函數(shù)庫的關(guān)鍵在于source命令。$ cat badtest4 #!/bin/bash # using a library file the wrong way ./myfuncs result=$(addem 10 15) echo "The result is $result" $ $ ./badtest4 ./badtest4: addem: command not found The result is
source命令不會(huì)創(chuàng)建新的shell,而是在當(dāng)前shell的上下文中執(zhí)行命令.
source命令稱作點(diǎn)號(hào)操作符。在shell腳本中運(yùn)行myfuncs庫文件,只需添加:
假定myfuncs庫文件和shell腳本位于同一目錄。否則需要使用正確路徑訪問該文件。. ./myfuncs
$ cat test14 #!/bin/bash . ./myfuncs value1=10 value2=5 result1=$(addem $value1 $value2) echo "The result of adding them is: $result1" $ $ ./test14 The result of adding them is: 15
6.7.在命令行中使用函數(shù)
有時(shí)候,在命令行界面用函數(shù)執(zhí)行一些十分復(fù)雜的操作.
6.7.1.命令行中創(chuàng)建函數(shù)
shell會(huì)解釋用戶輸入的命令,可以在命令行中直接定義一個(gè)函數(shù).
在命令行創(chuàng)建函數(shù)時(shí)要特別小心。如果給函數(shù)起了一個(gè)跟內(nèi)建命令或另一個(gè)命令相同的名字,那么函數(shù)就會(huì)覆蓋原來的命令。
- 單行方式
在命令行中定義函數(shù)時(shí),必須在每個(gè)命令后面加個(gè)分號(hào),用于界定命令的起止.$ function divem { echo $[ $1 / $2 ]; } $ divem 100 5 20
- 多行方式
定義時(shí),bash shell會(huì)使用次提示符’>'來提示輸入更多命令。使用這種方法,無須在每條命令的末尾放置分號(hào),只需按下回車鍵.
輸入函數(shù)尾部的花括號(hào)后完成函數(shù)的定義.$ function multem { > echo $[ $1 * $2 ] > } $ multem 2 5 10
在命令行中直接定義shell函數(shù)的一個(gè)明顯缺點(diǎn)是,在退出shell時(shí),函數(shù)也會(huì)消失。
在命令行創(chuàng)建函數(shù)時(shí)要特別小心。如果給函數(shù)起了一個(gè)跟內(nèi)建命令或另一個(gè)命令相同的名字,函數(shù)就會(huì)覆蓋原來的命令。
6.7.2.在.bashrc文件中定義函數(shù)
解決退出shell函數(shù)消失的問題.
將函數(shù)定義在每次新shell啟動(dòng)時(shí)都會(huì)重新讀取該函數(shù)的地方。
.bashrc文件,不管是交互式shell還是從現(xiàn)有shell啟動(dòng)的新shell,bash shell在每次啟動(dòng)時(shí)都會(huì)在用戶主目錄中查找這個(gè)文件。
- 直接定義函數(shù)
直接在用戶主目錄的.bashrc文件中定義函數(shù)。將函數(shù)放在文件末尾.
函數(shù)會(huì)在下次啟動(dòng)新的bash shell時(shí)生效。隨后就能在系統(tǒng)中的任意地方使用這個(gè)函數(shù)。$ cat .bashrc # .bashrc # Source global definitions if [ -r /etc/bashrc ]; then . /etc/bashrc fi function addem { echo $[ $1 + $2 ] } $
- 源引函數(shù)文件
只要是在shell腳本中,就可以用source命令(或別名即點(diǎn)號(hào)操作符)將庫文件中的函數(shù)添加到.bashrc腳本中.確保庫文件的路徑名正確.$ cat .bashrc # .bashrc # Source global definitions if [ -r /etc/bashrc ]; then . /etc/bashrc fi . /home/rich/libraries/myfuncs $
shell會(huì)將定義好的函數(shù)傳給子shell進(jìn)程,這些函數(shù)就能夠自動(dòng)用于該shell會(huì)話中的任何子shell腳本.
用源引庫文件,這些函數(shù)就可以在shell腳本中順暢運(yùn)行。
6.8.共享庫函數(shù)
在開源世界中,共享代碼是必不可少的,同樣適用于shell腳本函數(shù)??梢韵螺d各種shell腳本函數(shù)并將其用于自己的應(yīng)用程序中。
下載、安裝以及使用GNU shtool shell腳本函數(shù)庫。shtool庫提供了一些簡單的shell腳本函數(shù),可用于實(shí)現(xiàn)日常的shell功能,比如處理臨時(shí)文件和目錄、格式化輸出顯示等。
6.8.1.下載安裝
- 將GNU shtool庫下載并安裝到你的系統(tǒng)中.
wget http://ftp.gnu.org/gnu/shtool/shtool-2.0.8.tar.gz
- 將文件復(fù)制到主目錄中.
- 使用tar命令提取文件.
tar -zxvf shtool-2.0.8.tar.gz
- 進(jìn)入到解壓新創(chuàng)建的目錄
- 構(gòu)建庫文件
使用標(biāo)準(zhǔn)的configure命令和make命令$ ./configure $ make
configure命令會(huì)檢查構(gòu)建shtool庫文件所必需的軟件。發(fā)現(xiàn)了所需的工具,會(huì)使用工具路徑修改配置文件。
make命令負(fù)責(zé)構(gòu)建shtool庫文件。最終的shtool文件是一個(gè)完整的庫軟件包文件。
可以使用make命令測(cè)試庫文件
$ make test
Running test suite:
echo...........ok
... ... 略
OK: passed: 19/19
測(cè)試模式會(huì)測(cè)試shtool庫中所有的函數(shù)。如果全部通過了測(cè)試,就可以將庫安裝到Linux系統(tǒng)中的公用位置,這樣你的所有腳本就都能使用這個(gè)庫了。
以root用戶使用make命令的install選項(xiàng)完成安裝.
# make install
Password:
./shtool mkdir -f -p -m 755 /usr/local
... ...
./shtool install -c -m 644 sh.version /usr/local/share/shtool/sh.version
./shtool install -c -m 644 sh.path /usr/local/share/shtool/sh.path
# shtool -v
GNU shtool 2.0.8 (18-Jul-2008)
安裝成功,可以使用了.文章來源:http://www.zghlxwxcb.cn/news/detail-630359.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-630359.html
到了這里,關(guān)于【Linux命令行與Shell腳本編程】第十六章 Shell函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!