- 函數(shù)的基本含義
- 函數(shù)的定義和使用
- 數(shù)組
- 字符串處理
- 特殊的處理變量用法
一取劫、函數(shù)基本含義:
函數(shù):多條Shell命令組成的語(yǔ)句塊,實(shí)現(xiàn)代碼重用忌卤、模塊化編程
-
函數(shù)與Shell程序的區(qū)別:
- 函數(shù)不能獨(dú)立運(yùn)行扫夜,Shell程序可以獨(dú)立運(yùn)行
- 函數(shù)只能在Shell程序中運(yùn)行,Shell程序可以在其他Shell程序建立的子Shell中運(yùn)行
- 函數(shù)可以修改Shell中的變量驰徊,子Shell程序無(wú)法修改父Shell程序的變量
使用函數(shù)前必須對(duì)其定義笤闯,定義中需要闡明函數(shù)名和函數(shù)體
-
函數(shù)的定義:函數(shù)的名稱建議有一定含義,增加可讀性
函數(shù)定義的語(yǔ)法格式共有3種棍厂,效果相同- 格式1:
function f_name {
函數(shù)體
......
} - 格式2:
function f_name () {
函數(shù)體
......
} - 格式3:
f_name() {
函數(shù)體
......
}
- 格式1:
函數(shù)的使用:給出函數(shù)名颗味,則函數(shù)名位置自動(dòng)被替換為函數(shù)代碼
-
函數(shù)的定義和使用方式:
- 可以在交互式環(huán)境中直接定義函數(shù)
- 可以在腳本中定義和使用函數(shù)
- 可以把函數(shù)的定義編寫(xiě)在一個(gè)腳本文件中
-
函數(shù)的返回值:
- 函數(shù)體內(nèi)echo語(yǔ)句輸出值
- 函數(shù)體內(nèi)調(diào)用命令的輸出結(jié)果
-
函數(shù)的退出狀態(tài)碼
- 默認(rèn)狀態(tài):退出狀態(tài)碼取決于函數(shù)體執(zhí)行的最后一條命令的退出狀態(tài)碼
- 自定義退出狀態(tài)碼 return命令:
- return,默認(rèn)狀態(tài)的退出狀態(tài)碼:return前最后執(zhí)行命令的退出狀態(tài)碼
- return NUM:以指定的數(shù)字NUM(0-255)作為退出狀態(tài)碼牺弹,一般0指代成功浦马,1-255可以自定義各類錯(cuò)誤
二、函數(shù)的定義與使用詳解:
(一)函數(shù)的定義:
- 交互式環(huán)境定義
f_name () { //第一行輸至{回車
>函數(shù)體語(yǔ)句 //>是提示符张漂,后面輸入函數(shù)體語(yǔ)句晶默,回車換行繼續(xù)輸入
>函數(shù)體語(yǔ)句
> ......
>} //輸入}后回車定義本函數(shù)完畢
在腳本中定義函數(shù)
shell是解釋性語(yǔ)言,運(yùn)行時(shí)從上至下執(zhí)行語(yǔ)句鹃锈,故函數(shù)的定義語(yǔ)句必須在其被調(diào)用之前函數(shù)定義文件
使用函數(shù)文件中定義的函數(shù)前荤胁,必須先執(zhí)行函數(shù)定義文件,此時(shí)函數(shù)的定義將載入當(dāng)前shell環(huán)境中屎债,語(yǔ)法:. filename
或者source filename
(二)函數(shù)的使用
-
只需給出函數(shù)名即可調(diào)用函數(shù)
- set:查詢當(dāng)前所有定義的函數(shù)仅政,這些函數(shù)都已經(jīng)載入所在shell
語(yǔ)法:set f_name
, f_name:函數(shù)名稱 - unset:撤銷函數(shù)的定義盆驹,被撤銷函數(shù)的定義將從shell中卸載
語(yǔ)法:unset f_name
圆丹,f_name:函數(shù)名稱
- set:查詢當(dāng)前所有定義的函數(shù)仅政,這些函數(shù)都已經(jīng)載入所在shell
環(huán)境函數(shù):在子進(jìn)程中使用父進(jìn)程定義的函數(shù)
語(yǔ)法:
聲明環(huán)境函數(shù):export -f f_name
,f_name函數(shù)名稱
查看環(huán)境函數(shù):export -f
或者declare -xf
-
函數(shù)的參數(shù):函數(shù)可以接受參數(shù)躯喇,從而擴(kuò)展函數(shù)的使用功能
- 傳遞參數(shù)給函數(shù):在調(diào)用函數(shù)時(shí)辫封,在函數(shù)名后直接附加以空格分隔的給定參數(shù)
語(yǔ)法:f_name arg1 arg2 arg3...
,f_name:函數(shù)名稱廉丽;arg1,arg2,arg3:參數(shù) - 函數(shù)體內(nèi)調(diào)用參數(shù)倦微,使用位置變量$1, $2, $3以及一些特殊變量:$*, $@, $#
- 傳遞參數(shù)給函數(shù):在調(diào)用函數(shù)時(shí)辫封,在函數(shù)名后直接附加以空格分隔的給定參數(shù)
-
函數(shù)變量的作用域:
- 環(huán)境變量:在父進(jìn)程、子進(jìn)程均有效的變量正压,使用
export var_name
聲明 - 本地變量:僅在本進(jìn)程范圍內(nèi)有效的變量欣福,函數(shù)內(nèi)對(duì)本地變量的修改將影響到函數(shù)外
- 局部變量:僅在函數(shù)的生命周期內(nèi)有效,函數(shù)調(diào)用結(jié)束則自動(dòng)消失焦履,故函數(shù)內(nèi)對(duì)局部變量的修改對(duì)函數(shù)外無(wú)影響拓劝,使用
local var_name
聲明 - 當(dāng)本地與局部變量名稱相同時(shí)雏逾,從函數(shù)的聲明周期角度分析,函數(shù)體內(nèi)部使用局部變量運(yùn)算郑临,函數(shù)體外使用本地變量運(yùn)算栖博,兩個(gè)變量相互隔離
- 環(huán)境變量:在父進(jìn)程、子進(jìn)程均有效的變量正压,使用
-
函數(shù)的遞歸調(diào)用:函數(shù)調(diào)用自身
- 函數(shù)的遞回調(diào)用一般需要有結(jié)束條件,使子層函數(shù)的結(jié)果最終能夠返回至上層函數(shù)中
- 不同的語(yǔ)言的最大遞歸層數(shù)不同
- fork炸彈:不斷fork進(jìn)程的無(wú)限循環(huán)厢洞,最終耗盡系統(tǒng)資源
- 函數(shù)實(shí)現(xiàn)
:(){ :|:& };:
仇让,:冒號(hào)是函數(shù)名稱,本函數(shù)與下面的函數(shù)寫(xiě)法相同
bomb() { bomb | bomb & }; bomb
犀变,函數(shù)名為bomb - 腳本實(shí)現(xiàn)
#! /bin/bash ./$0|./$0&
- 函數(shù)實(shí)現(xiàn)
-
實(shí)驗(yàn):
漢諾塔問(wèn)題:三根柱子妹孙,在一根柱子上從下往上按照大小順序摞著N片盤(pán)子。要求把圓盤(pán)從下面開(kāi)始按大小順序重新擺放在另一根柱子上获枝。并且規(guī)定,在小圓盤(pán)上不能放大圓盤(pán)骇笔,在三根柱子之間一次只能移動(dòng)一個(gè)圓盤(pán)省店,利用函數(shù),實(shí)現(xiàn)N片盤(pán)的漢諾塔的移動(dòng)步驟分析:
想要把N個(gè)盤(pán)子從一個(gè)柱子移動(dòng)到另一個(gè)柱子笨触,可以分為三個(gè)步驟:(1)把N-1個(gè)盤(pán)子從柱子A移動(dòng)到柱子B懦傍;(2)把第N個(gè)盤(pán)子從柱子A移動(dòng)到柱子C;(3)把N-1個(gè)盤(pán)子從柱子B移動(dòng)到柱子C芦劣。而步驟1和步驟3都能夠再分解為如上的三個(gè)步驟粗俱,所以漢諾塔問(wèn)題是一個(gè)遞歸問(wèn)題。通過(guò)遞歸函數(shù)虚吟,可以實(shí)現(xiàn)輸出漢諾塔的移動(dòng)步驟寸认。代碼:
read -p "please type the layer of hannuota: " num
from="A"
via="B"
to="C"
#第2步的函數(shù)實(shí)現(xiàn)
move () {
echo "plate:$1 $2 --> $3"
}
#實(shí)現(xiàn)遞歸函數(shù)
hannuota () {
# echo num:$1 from:$2 via:$3 to:$4
if [ $1 -eq 1 ]; then
move $1 $2 $4
else
#遞歸過(guò)程具體實(shí)現(xiàn)
hannuota $[ $1-1 ] $2 $4 $3
move $1 $2 $4
hannuota $[ $1-1 ] $3 $2 $4
fi
}
#調(diào)用函數(shù)
hannuota $num $from $via $to
執(zhí)行結(jié)果如下:
三、數(shù)組:
(一)數(shù)組的定義:
數(shù)組:存儲(chǔ)多個(gè)元素的連續(xù)的內(nèi)存空間串慰,相當(dāng)于多個(gè)變量的集合
數(shù)組的索引:從0開(kāi)始編號(hào)偏塞,數(shù)字索引方式
數(shù)組的關(guān)聯(lián)索引:自定義索引,使用字母邦鲫、數(shù)字等符號(hào)作為索引灸叼,從bash 4.0開(kāi)始支持
稀疏數(shù)組:數(shù)組的索引編號(hào)不連續(xù),可以創(chuàng)建時(shí)不連續(xù)庆捺,也可能因數(shù)組的增刪操作而變得不連續(xù)
(二)數(shù)組的語(yǔ)法介紹:
聲明數(shù)組:普通數(shù)組和關(guān)聯(lián)數(shù)組一經(jīng)聲明不可互相轉(zhuǎn)換
普通數(shù)組:declare -a ARRAY_NAME
關(guān)聯(lián)數(shù)組:declare -A ARRAY_NAME古今,關(guān)聯(lián)數(shù)組必須先聲明才能被調(diào)用數(shù)組元素的賦值:
(1)給單個(gè)元素賦值:
ARRAY_NAME[#]=VALUE
(2)一次將數(shù)組元素賦值:
ARRAY_NAME=("VAL1" "VAL2" "VAL3" "VAL4" ...)
(3)給特定的數(shù)組元素賦值:
ARRAY_NAME=([0]="VAL1" [2]="VAL2" ...)
(4)交互式賦值:
read -a ARRAY_NAME顯示所有數(shù)組:
declare -a
(三)數(shù)組數(shù)據(jù)的處理:
引用數(shù)組元素:${ARRAY_NAME[#]}
注明:${ARRAY_NAME}相當(dāng)于${ARRAY_NAME[0]}引用數(shù)組所有元素:
${ARRAY_NAME[*]} 或者 ${ARRAY_NAME[@]}數(shù)組的長(zhǎng)度(數(shù)組元素的個(gè)數(shù))
${#ARRAY_NAME[*]} 或者 ${#ARRAY_NAME[@]}添加數(shù)組元素至數(shù)組尾部
ARRAY_NAME[${#ARRAY_NAME[*]}]=VALUE刪除數(shù)組元素
unset ARRAY_NAME[#]刪除數(shù)組
unset ARRAY_NAME數(shù)組切片
${ARRAY_NAME[@]:offset:number}
offset:跳過(guò)元素的個(gè)數(shù)
number:取出元素的個(gè)數(shù)實(shí)驗(yàn):如下圖所示,實(shí)現(xiàn)轉(zhuǎn)置矩陣matrix.sh
1 2 3 1 4 7
4 5 6 ===> 2 5 8
7 8 9 3 6 9
分析發(fā)現(xiàn)需要交換的數(shù)字其特點(diǎn)在于滔以,兩個(gè)數(shù)字所在位置的行號(hào)與列號(hào)正好相反捉腥。如數(shù)字2位于行1列2,而數(shù)字4位于行2列1醉者。由此但狭,可以分別采用兩次循環(huán)操作行號(hào)和列號(hào)披诗,并交換符合要求的數(shù)字。為了防止已經(jīng)交換的數(shù)字再次交換立磁,實(shí)際上需要虛幻的數(shù)字位于數(shù)字1至數(shù)字9所連接成的對(duì)角線上方數(shù)字即可呈队。
代碼如下:
#要求用戶輸入想要N*N的矩陣
read -p "please type the number of matrix: " matrix_num
#從0行0列開(kāi)始數(shù)組編號(hào),所以先對(duì)用戶輸入值自減1
let matrix_num--
num=1
#定義數(shù)組
declare -a matrix
#從1開(kāi)始為矩陣賦值
for i in `seq 0 $matrix_num`; do
for j in `seq 0 $matrix_num`; do
matrix[$i$j]=$num
let num++
done
done
#定義函數(shù)唱歧,實(shí)現(xiàn)矩陣打印
func() {
for p in `seq 0 $matrix_num`; do
for q in `seq 0 $matrix_num`; do
echo -ne "${matrix[$p$q]}\t"
done
echo
done
}
#調(diào)用函數(shù)宪摧,打印矩陣
func
echo
# 將矩陣轉(zhuǎn)置
for x in `seq 0 $matrix_num`; do
for y in `seq $x $matrix_num`; do
if ! [ $x -eq $y ]; then
temp=${matrix[$x$y]}
matrix[$x$y]=${matrix[$y$x]}
matrix[$y$x]=$temp
fi
done
done
#再次調(diào)用func函數(shù),打印矩陣
func
執(zhí)行結(jié)果如下:
四颅崩、字符串處理:
(一)字符串切片:
${#var}:返回字符串變量的長(zhǎng)度
${var:offset}:返回字符串從第offset個(gè)(不含第offset個(gè))到最后字符的部分
${var:offset:num}:返回字符串從第offset個(gè)(不含第offset個(gè))共num個(gè)字符長(zhǎng)度的部分
${var: -length}:返回字符串最右側(cè)的length個(gè)字符几于,冒號(hào)后有一個(gè)空格
${var:offset:-length}:返回字符串從第offset個(gè)(不含第offset個(gè))到距最右側(cè)共length個(gè)字符的部分
${var: -length:-offset}:從最右側(cè)向左取length個(gè)字符開(kāi)始,至距最右側(cè)offset個(gè)字符之間的字符沿后,-length前有一個(gè)空格
(二)基于模式取子字符串:
${var#*word}:刪除從字符串開(kāi)始至第一次出現(xiàn)word之間的所有字符
${var##*word}:貪婪模式沿彭,刪除從字符串開(kāi)始至最后一次出現(xiàn)word之間的所有字符
${var%word*}:刪除從最右側(cè)開(kāi)始至第一次出現(xiàn)word之間的所有字符
${var%%word*}:貪婪模式,刪除從最右側(cè)開(kāi)始至最后一次出現(xiàn)word之間的所有字符
(三)查找替換
${var/pattern/substr}:將查找到的第一次匹配pattern的字符串替換為substr
${var//pattern/substr}:將查找到的所有匹配pattern的字符串替換為substr
${var/#pattern/substr}:將行首匹配pattern的字符串替換為substr
${var/%pattern/substr}:將行尾匹配pattern的字符串替換為substr
(四)查找刪除
${var/pattern}:將查找到的第一次匹配pattern的字符串刪除
${var//pattern}:將查找到的所有匹配pattern的字符串刪除
${var/#pattern}:將行首匹配pattern的字符串刪除
${var/%pattern}:將行尾匹配pattern的字符串刪除
(五)大小寫(xiě)轉(zhuǎn)換
${var^^}:字符串全部轉(zhuǎn)換為大寫(xiě)
${var,,}:字符串全部轉(zhuǎn)換為小寫(xiě)
五尖滚、特殊的處理變量用法:
(一)聲明為有類型變量:declare 和 typeset喉刘,兩者等價(jià)
語(yǔ)法:
declare [選項(xiàng)] 變量名
-r 聲明或顯示只讀變量
-i 將變量定義為整型數(shù)
-a 將變量定義為數(shù)組
-A 將變量定義為關(guān)聯(lián)數(shù)組
-f 顯示此腳本前定義過(guò)的所有函數(shù)名及其內(nèi)容
-F 僅顯示此腳本前定義過(guò)的所有函數(shù)名
-x 聲明或顯示環(huán)境變量和函數(shù)
-l 聲明變量為小寫(xiě)字母
-u 聲明變量為大寫(xiě)字母
(二)eval命令:
功能:先掃描一次命令行執(zhí)行全部替換,再執(zhí)行命令
適用于一次掃描不能實(shí)現(xiàn)功能的變量漆弄,eval命令可以實(shí)現(xiàn)兩次掃描
(三)間接變量引用:
如果第一個(gè)變量的值是第二個(gè)變量的名字睦裳,從第一個(gè)變量引用第二個(gè)變量的值就稱為間接變量引用
實(shí)現(xiàn)方法:
eval tempvar=$$variable1
tempvar=${!variable1}
(四)創(chuàng)建臨時(shí)文件 mktemp命令:
功能:創(chuàng)建并顯示臨時(shí)文件,可避免沖突
語(yǔ)法:
mktemp [OPTION]... [TEMPLATE]
TEMPLATE: filename.XXXX撼唾,至少要出現(xiàn)三個(gè)
OPTION:
-d: 創(chuàng)建臨時(shí)目錄
-p DIR或--tmpdir=DIR:指明臨時(shí)文件所存放目錄位置
(五)安裝復(fù)制文件 install命令:
可以實(shí)現(xiàn)文件復(fù)制廉邑,所有者、所屬組修改倒谷,權(quán)限修改在一條命令中執(zhí)行
語(yǔ)法:
install [OPTION]... [-T] SOURCE DEST 單文件
install [OPTION]... SOURCE... DIRECTORY
install [OPTION]... -t DIRECTORY SOURCE...
install [OPTION]... -d DIRECTORY...創(chuàng)建空目錄選項(xiàng):
-m MODE蛛蒙,默認(rèn)755
-o OWNER
-g GROUP
(六)expect命令:
功能:實(shí)現(xiàn)自動(dòng)化交互式操作場(chǎng)景
expect 語(yǔ)法:
expect [選項(xiàng)] [ -c cmds] [ [ -[f|b] ] cmdfile] [ args ]選項(xiàng)
-c:從命令行執(zhí)行expect腳本,expect默認(rèn)交互式執(zhí)行
-d:可以輸出調(diào)試信息expect中相關(guān)命令
spawn:?jiǎn)?dòng)新的進(jìn)程
send:用于向進(jìn)程發(fā)送字符串
expect:從進(jìn)程接收字符串
interact:允許用戶交互
exp_continue:匹配多個(gè)字符串在執(zhí)行動(dòng)作后加此命令-
expect最常用的語(yǔ)法(tcl語(yǔ)言:模式-動(dòng)作)
單一分支模式語(yǔ)法:
expect “hi” {send “You said hi\n"}
匹配到hi后恨锚,會(huì)輸出“you said hi”宇驾,并換行多分支模式語(yǔ)法:
expect "hi" { send "You said hi\n" }
"hehe" { send “Hehe yourself\n" }
"bye" { send “Good bye\n" }
匹配hi,hello,bye任意字符串時(shí),執(zhí)行相應(yīng)輸出猴伶。等同如下:
expect {
"hi" { send "You said hi\n"}
"hehe" { send "Hehe yourself\n"}
"bye" { send “Good bye\n"}
}