目錄
函數
什么是函數
函數的語法
函數的調用
函數的返回值
函數的案例
函數變量的作用域
遞歸函數
函數庫文件
數組
定義數組語法
數組操作
獲取所有元素
獲取元素下標
獲取數組長度
獲取數組元素
數組添加元素
刪除數組元素
刪除數組
遍歷數組元素
數組案例
函數
什么是函數
? ? ? ? 所謂函數,與其他語言中的函數沒有太大的本質區別。它們是完成特定功能的代碼塊,這個代碼塊是可以重復使用的,并是一組命令或者語句組成
? ? ? ? 在Shell中,函數本質上就是將函數名稱與要實現的特殊功能的代碼進行引用的一種方式
在Shell中函數具有以下的優勢:
把相同的程序代碼定義函數,這樣就可以重復利用,從而提長開放的效率 |
增加了程序代碼段的可讀性和提升管理效率 |
可以實現程序功能的模塊化。使得程序具備通用性 |
函數的語法
在Shell中,函數具有以下的語法結構:
#完整結構
function 函數名稱() {指令或語句return [返回值]
}#簡化結構
function 函數名稱 {指令或語句return [返回值]
}#進一步簡化的結構
函數名稱() {指令或語句return [返回值]
}
函數的調用
? ? ? ? 在Shell中,調用函數之前,該函數必須存在
調用函數的基本語法如下:
函數名稱 [參數1 參數2 參數3 ......]
? ? ? ? 對于函數的調用,可以有以下方法:
$# | 獲取參數的個數 |
$1、$2、$3...... | 獲取是第幾個參數 |
$@ 或者 $* | 獲取所有的參數列表 |
示例:
? ? ? ? 定義一個名稱叫 fun 的函數,并且調用 fun 函數
[root@openEuler ~]# cat fun1.sh
#!/bin/bash# 定義一個名稱叫 fun 的函數
fun() {echo "the function has $# parameters"echo "all parameters $@"echo "first parameter $1"echo "second parameter $2"
}# 調用定義好的 fun 函數
fun hello world[root@openEuler ~]# bash fun1.sh
the function has 2 parameters
all parameters hello world
first parameter hello
second parameter world
[root@openEuler ~]#
注意:
? ? ? ? 在Shell中,函數是先定義再使用,如果是先使用再定義,就會報錯
報錯示例:
[root@openEuler ~]# cat fun1.sh
#!/bin/bash#先調用 fun 函數
fun hello world# 再定義 fun 函數
fun() {echo "the function has $# parameters"echo "all parameters $@"echo "first parameter $1"echo "second parameter $2"
}[root@openEuler ~]# bash fun1.sh
fun1.sh: line 3: fun: command not found
? ? ? ? 如果函數只聲明了,但是沒有調用這個函數,那么該函數不會執行。但是我們可以使用 . 或者 source 來先執行這個腳本,讓函數放到當前的 Shell 環境中,此時我們在 Shell 環境中就可以執行這個函數
示例:
[root@openEuler ~]# cat fun1.sh
#!/bin/bash#只聲明 fun 函數,但是沒調用函數
fun() {echo "the function has $# parameters"echo "all parameters $@"echo "first parameter $1"echo "second parameter $2"
}#將腳本中的函數放到當前shell 環境中
[root@openEuler ~]# source ./fun1.sh [root@openEuler ~]# fun 1 2
the function has 2 parameters
all parameters 1 2
first parameter 1
second parameter 2
函數的返回值
? ? ? ? 在 Shell 中,函數也是可以有返回值的,但是它和其他語言中的函數返回值不太相同
在函數中如果使用 return 語句來退出函數,并返回函數的值時,那么在函數外就需要使用 echo $? 來獲取返回的值 |
在函數中如果使用的是 echo 輸出,那么在函數外邊就可以使用 變量=$(函數名稱) 來獲取返回的值 |
注意:
? ? ? ? 在 Shell 中使用 return 返回的只能是整數值,而且范圍不能超過0~255,如果超過了則需要與256取模
示例1:
? ? ? ? 計算兩個參數的和
[root@openEuler ~]# cat fun2.sh
#!/bin/bash
sum1() {sum=$[$1 + $2]echo $sum
}
read -p "Please enter first number: " first
read -p "Please enter second number: " secondsum1 first second
#或者
res=$(sum1 first second)echo $res[root@openEuler ~]# bash fun2.sh
Please enter first number: 6
Please enter second number: 4
10
示例2:
? ? ? ? 獲取字符串的長度
[root@openEuler ~]# cat fun3.sh
#!/bin/bash
length() {str=$1len=0if [ "$1" != "" ]; thenlen=${#str}fi return $len
}
length "abc123"
echo "the string's length is $?"[root@openEuler ~]# bash fun3.sh
the string's length is 6
函數的案例
示例1:
? ? ? ? 將一個點分十進制格式的IP地址轉換成點分二進制格式
比如:255.255.255.255 ——> 11111111.11111111.11111111.11111111
[root@openEuler ~]# cat fun4.sh
#!/bin/bashdecimal_to_bin() {NUM=$1for i in {1..8}doSUM=$[NUM % 2]$SUMlet NUM/=2#((NUM=NUM/2))doneecho $SUM
}split_ip() {IP=$1for i in {1..4}donum=${IP%%.*} # IP=192.168.72.150 -> num=192#echo "num=$num"IP=${IP#*.} # IP=168.72.150 delete 192#echo "ip=$IP"BIN=$(decimal_to_bin num)#decimal_to_bin $numecho -n $BINdone
}read -p "Please enter a valid IP address: " INIPres=$(split_ip $INIP)
echo ${res%.*}[root@openEuler ~]# bash fun4.sh
Please enter a valid IP address: 192.168.72.112
11000000.10101000.01001000.01110000
示例2:
? ? ? ? 編寫一個腳本,實現判斷給定的 IP 地址范圍 [192.168.72.130~192.168.72.140] 是否在線
[root@openEuler ~]# cat fun5.sh
#!/bin/bashonline() {for i in {148..152}do if ping -c1 192.168.72.$i &>/dev/nullthen echo "192.168.72.$i is up"else echo "192.168.72.$i is unknow"fi done
} online[root@openEuler ~]# bash fun5.sh
192.168.72.148 is unknow
192.168.72.149 is unknow
192.168.72.150 is up
192.168.72.151 is up
192.168.72.152 is unknow
函數變量的作用域
示例1:
? ? ? ? 函數的變量是全局變量
[root@openEuler ~]# cat fun6.sh
#!/bin/bashstr="hello shell"
func() {str="openlab"echo $strstr2="hello"
}
echo "$str"
func
echo "$str"
echo "$str2"[root@openEuler ~]# bash fun6.sh
hello shell
openlab
openlab
hello
注意:
? ? ? ? 使用?$() 這種方式來執行命令時,變量值還是需要使用 $ 變量名的方式來獲取,當使用 $(())來做算術運算時,可以省略 $ 而直接使用變量名
示例:
#!/bin/basha=1
b=2
c=$[ $a + $b ] #`$a+$b`echo `expr $a + $b`echo $(expr $a + $b)echo $cd=$((a+b))
echo $d
示例2:
? ? ? ? 函數的變量如果希望是局部的,那么我們需要顯式的使用 local 來聲明
[root@openEuler ~]# cat fun7.sh
#!/bin/bashs="ni hao"
func() {local s="ni ye hao"echo $slocal s1="da jia wang shang hao"
}
echo "$s"
func
echo "$s"
echo "${s1}"
[root@openEuler ~]# bash fun7.sh
ni hao
ni ye hao
ni hao[root@openEuler ~]#
注意:
? ? ? ? 當使用 local 來聲明變量時,它就是一個局部變量,離開函數后,這個變量就消失了
遞歸函數
示例1:
? ? ? ? 根據用戶輸入的數值計算該數的階乘
[root@openEuler ~]# cat recursion.sh
#!/bin/bashrecursion() {if [ $1 -eq 1 ] ; thenresult=1elif [ $1 -gt 1 ] ; thenlocal n=$[ $1 - 1 ]recursion $nlet "result=$1 * $?"elseecho "The number is invalid"fireturn $result
}recursion $1
echo $?[root@openEuler ~]# bash recursion.sh 5
120
示例2:
? ? ? ? 使用函數遞歸 /var/log 目錄,如果是文件直接輸入文件名,如果是目錄則輸出目錄名稱并且輸出目錄下所有子目錄和文件名
[root@openEuler ~]# cat fact.sh
#!/bin/bashlist_file() {for f in $(ls $1)doif [ -d "$1/$f" ]; then #/var/log/anacondaecho "$2 directory $f"list_file "$1/$f" "├── $2"elseecho "$2 file $f"fidone
}
list_file $1 "├── "[root@openEuler ~]# bash fact.sh /var/log
├── directory anaconda
├── ├── file anaconda.log
├── ├── file dbus.log
├── ├── file dnf.librepo.log
├── ├── file hawkey.log
├── ├── file journal.log
├── ├── file lorax-packages.log
├── ├── file lvm.log
├── ├── file packaging.log
├── ├── file program.log
├── ├── file storage.log
├── ├── file syslog
├── ├── file X.log
├── directory audit
├── ├── file audit.log
├── file boot.log
├── file boot.log-20240324
........
函數庫文件
示例:
? ? ? ? (1)創建庫文件
[root@openEuler ~]# cat function_library.sh
#!/bin/bashaddition() {echo $[$1 + $2]
}substraction() {echo $[$1 - $2]
}multipication() {echo $[$1 * $2]
}division() {if [ $2 -eq 0 ]; thenecho "Division cannot be 0"elseecho $[$1 / $2]fi
}factorial() {if [ $1 -eq 1 ]; thenecho 1elif [ $1 -gt 1 ]; thenlocal tmp=$[$1-1]local res=$(factorial $tmp)echo $[$1 * res]elseecho "input value invalid"fi
}
? ? ? ? (2)在腳本中加載函數庫文件并且使用
[root@openEuler ~]# cat fl_test.sh
#!/bin/bash# load function_library.sh
source /root/function_library.shv1=10
v2=5r1=$(addition $v1 $v2)
r2=$(substraction $v1 $v2)r3=$(factorial $v2)echo $r1
echo $r2
echo $r3[root@openEuler ~]# bash fl_test.sh
15
5
120
數組
? ? ? ? 所謂數組,就是指將具有相同類型的若干變量按照一定的順序組織在一起的一種數據類型
定義數組語法
用小括號將變量值括起來賦值給數組變量,每個變量之間用空格分隔 | array=(value1 value2 value3 ...... valuen) |
使用小括號將變量值括起來,并且采用鍵值對的形式賦值 | array=([0]=one [1]=two ...... [n-1]=valuen) |
分別定義數組變量的值 | array[0]=one;array[1]=two;......array[n]=valuen |
使用動態的定義變量,并使用命令的輸出結果作為數組的內容 | array=(命令) |
通過 declare 語句來定義數組 | declare -a array |
數組操作
獲取所有元素
# 聲明數組,數組的名稱為 array,它里面有 6 個元素,分別是 1,2,3,4,5,6
[root@openEuler ~]# array=(1 2 3 4 5 6)
# 獲取數組所有無素,需要注意使用大括號將整個數組包起來
[root@openEuler ~]# echo $array[*]
1[*]
[root@openEuler ~]# echo ${array[*]}
1 2 3 4 5 6
[root@openEuler ~]# echo ${array[@]}
1 2 3 4 5 6
獲取元素下標
# 定義數組,數組的名稱為 array,它的第一個元素是 hello,第二個元素是 shell,第三個元素是 python
[root@openEuler ~]# array=([0]="hello" [1]="shell" [2]="python")
# 通過 !數組名稱[*|@] 來獲取元素對應的下標
[root@openEuler ~]# echo ${!array[@]}
0 1 2
[root@openEuler ~]# echo ${!array[*]}
0 1 2
獲取數組長度
# 定義數組,使用的是第三種語法
[root@openEuler ~]# array[0]="zhangsan"; array[1]="lisi"; array[2]="wangwu"
# 獲取數組中第一個元素的長度
[root@openEuler ~]# echo ${#array}
8
# 獲取數組元素個數(數組長度)
[root@openEuler ~]# echo ${#array[*]}
3
[root@openEuler ~]# echo ${#array[@]}
3
獲取數組元素
# 使用第四種語法:數組名稱=(命令) 來創建數組,然后通過下標獲取對應的元素
[root@openEuler ~]# array=(`seq 5`)
# 獲取數組中所有元素
[root@openEuler ~]# echo ${array[*]}
1 2 3 4 5
# 獲取數組中下標為 3 所對應的元素,如果存在則返回該下標對應的元素,如果不存在則返回空
[root@openEuler ~]# echo ${array[3]}
4
[root@openEuler ~]# echo ${array[6]}[root@openEuler ~]# echo $?
0
數組添加元素
# 使用第五種語法來定義數組,數組的名稱為 array
[root@openEuler ~]# declare -a array
# 給數組下標為0的位置添加元素
[root@openEuler ~]# array[0]=50
# 給數組下標為1的位置添加元素
[root@openEuler ~]# array[1]=35
# 給數組下標為2的位置添加元素
[root@openEuler ~]# array[20]=28
# 獲取數組中所有元素
[root@openEuler ~]# echo ${array[*]}
50 35 28# 使用 -A 的方式來定義數組
[root@openEuler ~]# declare -A arr
[root@openEuler ~]# arr[one]=15
[root@openEuler ~]# arr[two]=20
[root@openEuler ~]# arr[thr]=30
[root@openEuler ~]# echo ${arr[@]}
30 20 15# 獲取下標對應的元素
[root@openEuler ~]# echo ${array[1]}
35
[root@openEuler ~]# echo ${arr[two]}
20
刪除數組元素
# 定義數組
[root@openEuler ~]# array=(10 20 30 40 50)
# 獲取數組中所有元素
[root@openEuler ~]# echo ${array[@]}
10 20 30 40 50
# 刪除數組中下標為2的元素
[root@openEuler ~]# unset array[2]
# 驗證是否已經刪除
[root@openEuler ~]# echo ${array[*]}
10 20 40 50
[root@openEuler ~]# echo ${#array[*]}
4
刪除數組
# 定義數組
[root@openEuler ~]# array=(10 20 30 40 50)
# 獲取數組長度
[root@openEuler ~]# echo ${#array[*]}
5
# 刪除數組
[root@openEuler ~]# unset array
# 驗證數組是否刪除
[root@openEuler ~]# echo ${#array[@]}
0
遍歷數組元素
[root@openEuler ~]# cat array.sh
#!/bin/bashfiles=(`ls $1`)
for((i=0;i<${#files[*]};i++)); doecho ${files[$i]}
done[root@openEuler ~]# bash array.sh
array.sh
fact.sh
fl_test.sh
fun1.sh
fun2.sh
fun3.sh
fun4.sh
fun5.sh
fun6.sh
fun7.sh
function_library.sh
ips
myfile
mytest.sh
recursion2.sh
recursion.sh
數組案例
示例1:
? ? ? ? 從標準輸入讀取 n 次字符串,每次輸入的字符串保存在數組 array 中
[root@openEuler ~]# cat array1.sh
#!/bin/bash
i=0
n=5
while [ "$i" -lt $n ]; doecho "Please input string... `expr $i + 1`"read array[$i]b=${array[$i]}echo "$b"i=`expr $i + 1`
done
[root@openEuler ~]# bash array1.sh
Please input string... 1
1
1
Please input string... 2
2
2
Please input string... 3
3
3
Please input string... 4
4
4
Please input string... 5
5
5
示例2:
? ? ? ? 將字符串中的字母逐個放入數組,并輸出到標準輸出
#!/bin/bashstrs="helloworldshell"
declare -a arrayfor ((i=0;i<${#strs};i++)); doarray[$i]=${strs:$i:1}
donefor i in ${array[@]}; doecho ${i}
done
示例3:
? ? ? ? 將1~3這3個數字存到數組中,分別乘以8后再依次輸出
#!/usr/bin/basharray=(`seq 3`)for ((i=0; i<${#array[@]}; i++)); doecho $[${array[$i]}*8]
done
示例4:
? ? ? ? 輸出如下內容中字母數不大于6的單詞
cat is favorite to eat fish
#!/bin/basharray=(cat is favorite to eat fish)for i in ${array[*]}; doif [ ${#i} -le 6 ]; thenecho $ifi
done