函數介紹(function用法)
1、function用法
1、函數function是由若干條shell命令組成的語句塊,實現代碼重用和模塊化編程。
2、它與shell程序形式上是相似的,不同的是它不是一個單獨的進程,不能獨立運 行,而是shell程序的一部分,定義函數只對當前的會話窗口有效,如果再打開一個窗口再定義另外一個函數,就對另一個窗口有效,兩者互不影響。
3、函數和shell程序比較相似,區別在於以下兩種:
(1)Shell程序在子Shell中運行。
(2)而Shell函數在當前Shell中運行。因此在當前Shell中,函數可以對shell中變量進行修改。
2、定義函數
函數由兩部分組成:函數名和函數體
help function 語法一: f_name (){ ...函數體... } 語法二: function f_name { ...函數體... } 語法三: function f_name () { ...函數體... }
可以使用declare -F 選項進行查看所有定義的函數,用unset 加上變量名 就可以刪除定義的變量
3、函數的定義和使用:
1、函數的定義和使用:
(1)可在交互式環境下定義函數
(2)可將函數放在腳本文件中作爲它的一部分
(3)可放在只包含函數的單獨文件中
2、調用:函數只有被調用纔會執行
調用:給定函數名
函數名出現的地方,會被自動替換爲函數代碼
3、函數的生命週期:被調用時創建,返回時終止
4、函數返回值
函數有兩種返回值:
1、函數的執行結果返回值:
(1) 使用echo等命令進行輸出
(2) 函數體中調用命令的輸出結果
2、函數的退出狀態碼:
(1) 默認取決於函數中執行的最後一條命令的退出狀態碼
(2) 自定義退出狀態碼,其格式爲:
return 從函數中返回,用最後狀態命令決定返回值:
(1)return 0 無錯誤返回。
(2)return 1-255 有錯誤返回
5、使用函數文件
1、可以將經常使用的函數存入函數文件,然後將函數文件載入shell
2、文件名可任意選取,但最好與相關任務有某種聯繫。例如:functions.main
3、一旦函數文件載入shell,就可以在命令行或腳本中調用函數。可以使用set命 令查看所有定義的函數,其輸出列表包括已經載入shell的所有函數
4、若要改動函數,首先用unset命令從shell中刪除函數。改動完畢後,再重新載 入此文件
6、刪除shell函數
1、現在對函數做一些改動後,需要先刪除函數,使其對shell不可用。使用unset命 令完成刪除函數
2、命令格式爲: unset function_name
示例: unset findit
再鍵入set命令,函數將不再顯示
3、環境函數
(1)使子進程也可使用
(2)聲明:export -f function_name
(3)查看:export -f 或 declare -xf
7、函數參數
函數可以接受參數: 傳遞參數給函數:調用函數時,在函數名後面以空白分隔給定參數列表即可;
例如“testfunc arg1 arg2 ...”
在函數體中當中,可使用$1, $2, ...調用這些參數;還可以使用$@, $*, $# 等特殊變量
8、函數變量
變量作用域:
環境變量:當前shell和子shell有效
本地變量:只在當前shell進程有效,爲執行腳本會啓動專用子shell進程; 因此,本地變量的作用範圍是當前shell腳本程序文件,包括腳本中的函數
局部變量:函數的生命週期;函數結束時變量被自動銷燬
注意:如果函數中有局部變量,如果其名稱同本地變量,使用局部變量
在函數中定義局部變量的方法:local NAME=VALUE
實例1:
第一種寫法:如果命令過多,這行執行不太方便
#!/bin/bash func_os_version () { # 定義一個function函數名爲func_os_version,然後在大括號裏邊定義命令,取出操作系統的版本號,類似於定義別名一樣 sed -nr 's/.* ([0-9]+)\..*/\1/p' /etc/redhat-release } echo OS version is `func_os_version` # 直接寫上定義函數名稱,或者用echo 加上反向單引號進行輸出結果
查看輸出結果:
[root@centos-7 ~]# bash osversion.sh OS version is 7
第二種寫法:將定義的函數存放到文件中,並將要執行的腳本與定義的函數以及定義函數的文件名進行關聯
[root@centos-7 ~]# cat functions # 將定義的函數放到functions文件中 func_os_version () { sed -nr 's/.* ([0-9]+)\..*/\1/p' /etc/redhat-release } [root@centos-7 ~]# cat osversion.sh # 將要執行腳本的函數名和上面定義函數名的文件進行關聯 #!/bin/bash source functions # source functions是關聯上面的文件 func_os_version # 關聯functions裏邊定義的函數名 [root@centos-7 ~]# chmod +x osversion.sh # 對腳本加上執行權限 [root@centos-7 ~]# ./osversion.sh # 查看此時的執行結果即可 7
實例2:
第一步:先定義functions函數文件
[root@centos-7 data]# cat functions # 定義functions函數文件 func_is_digit(){ if [ ! "$1" ];then # 如果輸入的信息不是空,就爲真,但又不是數字 echo "Usage:func_is_digit number" # 請輸入數字 return 10 elif [[ $1 =~ ^[[:digit:]]+$ ]];then # 如果輸入是數字 return 0 # return 0 返回的是正確結果,但是不會推出腳本 else echo "Not a digit" # 如果上面都不是,就提醒不是數字 return 1 fi }
第二步:調用functions函數文件,並對不同的成績分段進行判斷
[root@centos-7 data]# cat score.sh #!/bin/bash source /data/functions # 調用指定的函數文件的絕對路徑 read -p "Input your score:" SCORE func_is_digit $SCORE # 直接調用上面的functions文件 if [ $? -ne 0 ];then #判斷上面的命令執行不等於0(不成功)就退出 exit else if [ $SCORE -lt 60 ];then # 如果成功了,對成績的三種判斷如下。 echo "You are loser" elif [ $SCORE -lt 80 ];then echo "soso" else echo "very good" fi fi
實例3
生產中function配合case語法:
#!/bin/bash #Author: liupengju #date: 2020-06-22 #TEL: xxxxxxxxxx #代碼發佈與回滾 set -e set -u #adx代碼部署變量定義 ADX_DIR=/gnome/adx adx_new_version="gnome-adx-0.0.1-SNAPSHOT-jar-with-dependencies.jar" ADX_NEW_MD5=`md5sum $adx_new_version | awk '{ print $1 }'` #此行需要修改爲cf平臺的md5碼 ADX_CHK_MD5="43bcfe7594f083a8653126e0896b93ac" #directAd代碼部署變量定義 direct_DIR=/gnome/directAd/ direct_version="direct-ad-0.0.1-SNAPSHOT-jar-with-dependencies.jar" direct_MD5=`md5sum $direct_version | awk '{ print $1 }'` #direct_old_version=$(ls -l |tail -n1 | awk '{print $9}') #此行需要修改爲cf平臺的md5碼 direct_CHK_MD5="03c3c2fc62b2edfc92e548351010ee9f" ##########部署directAd代碼############################# fun_copy_direct_code(){ mv $direct_DIR/$direct_version $direct_DIR/bak/${direct_version}_$(date +"%F-%T") echo "-----上一個版本已經移動到備份目錄" cp /data/$direct_version $direct_DIR && echo "-----代碼複製成功!!!" } fun_chk_direct_code(){ if [[ "$direct_MD5" == "$direct_CHK_MD5" ]];then echo "-----代碼校驗成功" && echo "代碼部署成功後MD5值爲:$direct_MD5" else echo "-----代碼校驗失敗" && exit fi } fun_deploy_direct_restart(){ #$direct_DIR/restart.sh systemctl restart httpd systemctl restart nginx echo "後端服務重啓成功!!!" } fun_chk_direct_port1(){ #驗證端口存活狀態 PORT1=`ss -nlt|grep 8080 |awk -F"[[:space:]]+|:" '{ print $7}'` PORT2=`ss -nlt|grep 8182 |awk -F"[[:space:]]+|:" '{ print $7}'` for port in $PORT1 $PORT2;do echo "The port is:$port------監聽端口正常" done } #############回滾direct代碼################################### fun_rollback_direct_code(){ cd $direct_DIR/bak direct_old_version=$(ls -l |tail -n1 | awk '{print $9}') # 提取上一個版本的jar包 mv $direct_DIR/${direct_version} $direct_DIR/bak/${direct_version}_$(date +"%F-%T") mv $direct_DIR/bak/${direct_old_version} $direct_DIR/${direct_version} echo "------舊版本代碼移動成功" direct_old_MD5=$(md5sum $direct_DIR/${direct_version} | awk '{print $1}') echo "代碼回滾後MD5值爲:$direct_old_MD5" } fun_rollback_direct_restart(){ #$direct_DIR/restart.sh systemctl restart httpd systemctl restart nginx echo "--------後端服務重啓成功" } fun_chk_direct_port2(){ #驗證端口存活狀態 PORT1=`ss -nlt|grep 8080 |awk -F"[[:space:]]+|:" '{ print $7}'` PORT2=`ss -nlt|grep 8182 |awk -F"[[:space:]]+|:" '{ print $7}'` for port in $PORT1 $PORT2;do echo "The port is:$port------端口監聽正常" done } #####################adx代碼部署######################################## fun_copy_adx__code(){ mv $ADX_DIR/$adx_new_version $ADX_DIR/bak/${adx_new_version}_$(date +"%F-%T") echo "-----上一個版本已經移動到備份目錄" cp /data/$adx_new_version $ADX_DIR && echo "-----代碼複製成功!!!" } fun_chk_adx_code(){ if [[ "$ADX_NEW_MD5" == "$ADX_CHK_MD5" ]];then echo "-----代碼校驗成功" && echo "代碼部署成功後MD5值爲:$ADX_NEW_MD5" else echo "-----代碼校驗失敗" && exit fi } fun_deploy_adx_restart(){ #$ADX_DIR/restart.sh systemctl restart httpd systemctl restart nginx echo "後端服務已經啓動!!!" } #驗證端口存活狀態 fun_chk_adx_port1(){ PORT1=`ss -nlt|grep 8080 |awk -F"[[:space:]]+|:" '{ print $7}'` PORT2=`ss -nlt|grep 8182 |awk -F"[[:space:]]+|:" '{ print $7}'` for port in $PORT1 $PORT2;do echo "The port is:$port------監聽的端口正常啓動" done } ###################################adx代碼回滾########################### fun_rollback_adx_code(){ cd $ADX_DIR/bak adx_old_version=$(ls -l |tail -n1 | awk '{print $9}') mv $ADX_DIR/${adx_new_version} $ADX_DIR/bak/${adx_new_version}_$(date +"%F-%T") mv $ADX_DIR/bak/${adx_old_version} $ADX_DIR/${adx_new_version} echo "------舊版本代碼移動成功" adx_old_MD5=$(md5sum $ADX_DIR/${adx_new_version} | awk '{print $1}') echo "代碼回滾後MD5值爲:$adx_old_MD5" } fun_rollback_adx_restart(){ #$ADX_DIR/restart.sh systemctl restart httpd systemctl restart nginx echo "--------後端服務已經啓動" } fun_chk_adx_port2(){ #驗證端口存活狀態 PORT1=`ss -nlt|grep 8080 |awk -F"[[:space:]]+|:" '{ print $7}'` PORT2=`ss -nlt|grep 8182 |awk -F"[[:space:]]+|:" '{ print $7}'` for port in $PORT1 $PORT2;do echo "The port is:$port-------端口監聽正常" done } case $1 in direct_deploy) fun_copy_direct_code fun_chk_direct_code fun_deploy_direct_restart fun_chk_direct_port1 ;; direct_rollback) fun_rollback_direct_code fun_rollback_direct_restart fun_chk_direct_port2 ;; adx_deploy) fun_copy_adx__code fun_chk_adx_code fun_deploy_adx_restart fun_chk_adx_port1 ;; adx_rollback) fun_rollback_adx_code fun_rollback_adx_restart fun_chk_adx_port2 ;; esac
實例4:
#!/bin/bash #Auth: liupengju #TEL: xxxxx ########部署完成校驗####### ####驗證adserver版本號############# fun_chk_adx_version(){ ansible adx -m shell -a 'md5sum /gnome/adx/gnome-adx-0.0.1-SNAPSHOT-jar-with-dependencies.jar' |awk '{print $1}'|sort |head -n62 |tee version_adx |cat -n adx_version=$(ansible adx -m shell -a 'md5sum /gnome/adx/gnome-adx-0.0.1-SNAPSHOT-jar-with-dependencies.jar' |awk '{print $1}'|sort |tail -n62 |uniq -c|awk '{print $2}') echo -e "\e[1;32m新發布的版本號爲:$adx_version\e[0m" version1=$(diff metadata version_adx) if [ -z $version1 ];then echo -e "\e[1;32m代碼部署成功 \e[0m" else echo -e "\e[1;31m請檢查錯誤 \e[0m" fi } ####驗證directAd版本號############ fun_chk_direct_version(){ ansible adx -m shell -a ' md5sum /gnome/directAd/direct-ad-0.0.1-SNAPSHOT-jar-with-dependencies.jar'|awk '{print $1}'|sort |head -n62 |tee version_direct |cat -n direct_version=$(ansible adx -m shell -a 'md5sum /gnome/directAd/direct-ad-0.0.1-SNAPSHOT-jar-with-dependencies.jar'|awk '{print $1}'|sort |tail -n62 |uniq -c|awk '{print $2}') echo -e "\e[1;32m新發布的版本號爲:$direct_version\e[0m" version2=$(diff metadata version_direct) if [ -z $version2 ];then echo -e "\e[1;32m代碼部署成功 \e[0m" else echo -e "\e[1;31m請檢查錯誤 \e[0m" fi } ###驗證8080端口狀態############### fun_chk_8080_port(){ chk_ip_8080=$(ansible adx -m shell -a ' netstat -ntulp |grep 8080' |awk '{print $1}' |egrep "[0-9]+\.*" |sort | tee data_8080.bak |cat -n) DIR_8080=$(diff metadata data_8080.bak) if [ -z $DIR_8080 ];then echo -e "\e[1;32m端口檢查成功,端口號:8080 \e[0m" else echo -e "\e[1;31m請檢查錯誤 \e[0m" fi } ####驗證8182端口狀態############# fun_chk_8182_port(){ chk_ip_8182=$(ansible adx -m shell -a ' netstat -ntulp |grep 8182' |awk '{print $1}' |egrep "[0-9]+\.*" |sort |tee data_8182.bak |cat -n) DIR_8182=$(diff metadata data_8182.bak) if [ -z $DIR_8182 ];then echo -e "\e[1;32m端口檢查成功,端口號:8182 \e[0m" else echo -e "\e[1;31m請檢查錯誤 \e[0m" fi } case $1 in adx) fun_chk_adx_version fun_chk_8080_port fun_chk_8182_port ;; direct) fun_chk_direct_version fun_chk_8080_port fun_chk_8182_port ;; esac