Shell編程之select循環&函數詳解

一、select循環

       功能:主要用于創建菜單,菜單按數字順序排列。并將PS3變量的值用作用戶輸入提示。用戶的選擇被保存在內置變量REPLY中。也可以和case語句結合,在select循環中對用戶的輸入作出判斷并處理。

       注意:select循環為無限循環,因此需要給出循環退出條件。

例1:讓用戶選擇其來自哪個省市

#!/bin/bash
#

echo "where are you come from"
PS3="i came from :"
declare -a cm=('beijing' 'shanghai' 'hainan' 'hebei' 'hunan')
select path in ${cm[@]} 
do
	break
done
echo "you are from $path"

blob.png

 例2:詢問用戶是哪個足球俱樂部的球迷,并顯示該俱樂部的教練。當用戶輸入quit時,退出。

#!/bin/bash
#

echo "Which football club is your favorite(quit to exit):"
PS3="my favorite is : "
select path in 'ManUnited' 'Barcelona' 'Chelsea' 'RealMadrid' 'quit'
do
	case $path in
		ManUnited)
		echo "you are $path fans"
		echo "$path coah is Jose mourinho"
		;;
		Barcelona)
		echo "you are  $path fans"
		echo "$path coah is Enrique"
		;;
		Chelsea)
		echo "you are  $path fans"
		echo "$path coah is Conti"
		;;
		RealMadrid)
		echo "you are  $path fans"
		echo "$path coah is Zidane"
		;;
		quit)
		echo "See you..."
		exit
		;;
		*)
		echo "Unknown option."
		continue
		;;
	esac
done

blob.png

 

二、函數

       介紹:函數是由若干條shell命令組成的語句塊,實現代碼重用和模塊化編程。

       應用場景:在編寫shell腳本時,有些代碼會被反復重用多次,把這些可能重復使用的代碼寫成函數,這樣就可以通過函數名調用來高效、重復地利用。另外,當shell腳本功能比較復雜時,可以將腳本劃分為多個模塊,不同模塊可以寫成不同的函數。

       2.1函數的語法格式:

              格式1、

                     f_name () {

                            函數體…

}

             

              格式2、

                     function f_name  {

                            函數體…

}

       2.2函數的生命周期:被調用時創建,返回時終止。

       2.3函數的調用:

              函數要能被調用,需在調用前進行定義。調用時直接鍵入函數名即可。例:

blob.png

              若不調用函數,則函數不會被執行。

blob.png 

       2.4函數的返回值: 

       分為兩種

              a、正常返回的數值:

                     (1)函數中的打印語句,如echo、print

                     (2)函數中命令的執行結果 

示例1:函數執行成功之后,會將用戶輸入的指令輸出

blob.png

如何獲取函數的輸出。有時候我們需要對函數正常輸出的數值進行處理,這時可以通過下面的方式獲取函數的輸出

示例2:將函數執行之后的輸出保存,進行處理

blob.png

              b、執行狀態返回值:

                     (1)取決于函數中執行的最后一條語句的執行狀態

                     (2)也可通過return自定義

                            return N(0-255)

              在示例3中,可以觀察到,函數的執行狀態取決于函數中執行的最后一條語句的執行狀態;但是沒辦法判斷函數中的其他語句是否執行成功,當需要根據函數中不同的語句的執行狀態做出判斷;來決定后續的操作時,需要用到return。如示例4。

#!/bin/bash
#
user_input () {
	read -p "please enter an excuteable command : " cmd
	echo $cmd
	ls /etc/justfortest
}
user_input
echo "Funtion status is $?"

blob.png

在示例4中,需要判斷用戶輸入的用戶是否存在,存在時,返回5的狀態值;用戶不存在時,添加用戶,根據添加用戶的命令的執行狀態來判斷添加是否成功。

blob.png 

       2.5在腳本中調用函數:

              在一個腳本中想要調用寫在另一個腳本中的函數,同過source  ”腳本名“來實現

 cacufun.sh腳本內容如下:cacufun.sh定義了加減乘除4中運算的函數

#!/bin/bash
#
addtion_num() {
	local res=`echo "$1 $2 $3"| bc`
	echo "result is $res"
}

subtract_num() {
	local res=`echo "$1 $2 $3"| bc`	
	echo "result is $res"
}

multiplication_num() {
	local res=`echo "$1 $2 $3"| bc`	
	echo "result is $res"
}

devision_num() {
	local res=`echo "$1 $2 $3"| bc`	
	echo "result is $res"
}

在cacutest.sh腳本中調用cacufun.sh腳本中的函數,實現對用戶輸入數據的運算。

#!/bin/bash
#
source /root/bin/practice/cacufun.sh

read -p "enter two int number to caculate: " num1 num2 num3
case $num2 in
	+)
	echo "$num1 $2 $num3 " `addtion_num $num1 $num2 $num3`
	;;
	-)
	echo "$num1 $2 $num3 " `substract_num $num1 $num2  $num3`
	;;
	*)
	echo "$num1 $2 $num3 " `multiplication_num $num1 $num2 $num3`
	;;
	/)
	cho "$num1 $2 $num3 " `devision_num $num1 $num2 $num3`
	;;
	*)
	echo "wrong option"
	exit 123
esac

blob.png 

       2.6函數參數:

              函數可以使用類似于調用腳本位置參數來調用函數的參數

              函數的參數表示:

                     $1,$2

                     $#

                     $@,$*

       函數中的$1,$2…指的是傳遞給函數的參數,而不是傳遞個腳本的參數

 blob.png

       2.7 shell腳本中的變量作用域:

              1、在函數中使用了在主程序中聲明的變量,重新賦值會直接修改主程序中的變量。

              2、如果想讓函數中的變量與主程序中的變量沖突,在函數中聲明變量時,使用local修飾,將變量聲明為局部變量,其作用域僅限于當前函數。

              3、變量被聲明的位置決定了其作用域,

                     3.1 在函數中使用了在主程序中沒有聲明的變量,在函數執行結束后即被撤銷,無論是否使用local修飾符

                     3.2 在函數中聲明了主程序中聲明過的變量,這兩個變量為不同的變量。函數中的變量在執行結束后即被撤銷。

       2.8 shell腳本中變量的查找順序:

              1、內層函數本身

              2、外層還是定義的

              3、主程序

              4、shell環境變量

      

2.9 函數的遞歸:

       函數直接或調用自身

       示例:

       斐波那契數列又稱黃金分割數列,因數學家列昂納多· 斐波那契以兔子繁殖為例子而引入,故又稱為“兔子數列”,指的是這樣一個數列:0 、1、1 、2 、3 、5 、8 、13 、21 、34 、…… ,斐波納契數列以如下被以遞歸的方法定義:F (0 )=0 ,F (1 )=1 ,F (n )=F(n-1)+F(n-2) (n≥2) )

寫一個函數,求n階斐波那契數列

#!/bin/bash
#

fab () {
	if [[ $1 -eq 1 || $1 -eq 2 ]];then
		echo -n "1 "
	else
		echo -n "$[$(fab $[$1-1])+$(fab $[$1-2])] "
	fi
}

for i in $(seq 1 $1)
do
	fab $i
done
echo

blob.png


三、實戰演練

1、編寫服務腳本/root/bin/testsrv.sh,完成如下要求

(1) 腳本可接受參數:start, stop, restart, status

(2) 如果參數非此四者之一,提示使用格式后報錯退出

(3) 如是start:則創建/var/lock/subsys/SCRIPT_NAME, 并顯示“啟動成功”

考慮:如果事先已經啟動過一次,該如何處理?

(4) 如是stop:則刪除/var/lock/subsys/SCRIPT_NAME, 并顯示“停止完成”

考慮:如果事先已然停止過了,該如何處理?

(5) 如是restart,則先stop, 再start

考慮:如果本來沒有start,如何處理?

(6) 如是status, 則如果/var/lock/subsys/SCRIPT_NAME文件存在,則顯示“SCRIPT_NAMEis running…”

如果/var/lock/subsys/SCRIPT_NAME文件不存在,則顯示“SCRIPT_NAME is stopped…”

其中:SCRIPT_NAME為當前腳本名

#!/bin/bash
#
srv_file=/var/lock/subsys/$0
srv_name=`basename $0`

usage_srv() {

	if [[ $1 -lt 1  || $1 -ge 2 ]];then
		echo "Wrong option:"
		echo "Usage : $srv_name start|stop|restart|status"
		exit 123
	fi

}


start_srv() {

	if [ -f $srv_file ];then
		echo "service $srv_name already started"
	else
		touch $srv_file && echo "start $srv_name finished"
	fi
		
}
	
stop_srv() {

	if [ ! -f $srv_file ];then
		echo "service $srv_name already stopped"
	else
		rm -f $srv_file &>/dev/null && echo "stop $srv_name finished"
	fi

}

status_srv() {

	if [ -f $srv_file ];then
		echo "service $srv_name is running"
	else
		echo "service $srv_name was stopped"
	fi

}


case $1 in
	start)
		start_srv $1
		;;
	stop)
		stop_srv $1
		;;
	restart)
		stop_srv $1
		start_srv $1
		;;
	status)
		status_srv $1
		;;
	*)
		usage_srv $#
	;;
esac

blob.png

2、編寫腳本/root/bin/copycmd.sh

(1) 提示用戶輸入一個可執行命令名稱;

(2) 獲取此命令所依賴到的所有庫文件列表

(3) 復制命令至某目標目錄(例如/mnt/sysroot)下的對應路徑下;

如:/bin/bash ==> /mnt/sysroot/bin/bash

/usr/bin/passwd==> /mnt/sysroot/usr/bin/passwd

(4) 復制此命令依賴到的所有庫文件至目標目錄下的對應路徑下:

如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2

(5)每次復制完成一個命令后,不要退出,而是提示用戶鍵入新的要復制的命令,并重復完成上述功能;

直到用戶輸入quit退出

#!/bin/bash
#

f_dir=/mnt/sysroot

cmd_input () {
	while true
	do
		read -p "Please input an excuteable command to backup (quit to exit): " cmd
		if [[ -z $cmd ]];then
			echo "wrong option,try again..."
			continue
		elif [[ $cmd == "quit" ]];then
			exit 88
		elif ! which --skip-alias $cmd &>/dev/null;then
			echo "No such command,try again..."
			continue
		else
			break
		fi
	done

}

cp_cmd() {

	cmd_path=`which  --skip-alias $cmd`
	cmd_dir=`dirname $cmd_path`
	[ ! -d $f_dir$cmd_dir ] && mkdir -p $f_dir$cmd_dir 
	cp $cmd_path $f_dir$cmd_dir && echo "backup $cmd finished"

}

cp_cmd_lib() {

	cmd_lib=`ldd $cmd_path`
	for path in $cmd_lib
	do
		cmd_lib_dir=`echo $path | grep -o -E '/[^[:space:]]+.*/'`
		if [[ ! -d $f_dir$cmd_lib_dir ]];then
			mkdir -p $f_dir$cmd_lib_dir && cp $path $f_dir$cmd_lib_dir &> /dev/null
		else
			cp $path $f_dir$cmd_lib_dir &> /dev/null
		fi
	done
	echo "backup ${cmd}'s library finished"

}

main() {

	while true
	do
		cmd_input  
		cp_cmd
		cp_cmd_lib
	done

}

main

原創文章,作者:M20-1鐘明波,如若轉載,請注明出處:http://www.www58058.com/38011

(0)
M20-1鐘明波M20-1鐘明波
上一篇 2016-08-21
下一篇 2016-08-21

相關推薦

  • N23_第六周

    1、復制/etc/rc.d/rc.sysinit文件至/tmp目錄,將/tmp/rc.sysinit文件中的以至少一個空白字符開頭的行的行首加#;:%s/^[[:blank:]]\+.*/\0#/g 2、復制/boot/grub/grub.conf至/tmp目錄中,刪除/tmp/grub.conf文件中的行首的空白字符;:%s/^[[:space:]]\+/…

    Linux干貨 2017-02-28
  • 磁盤管理

    設備類型分為字符設備和塊設備 主設備號用來標識設備類型,次設備號標識同一類型下的不同設備 硬盤設備命名: scsi,sata,sas,usb:/dev/sd 不同設備/dev/sda  /dev/sdb 同一設備不同分區:/dev/sda1,/dev/sdb2…… 硬盤: 一片磁盤的一面叫做盤面,一張盤片有兩個盤面 每個盤面有一個磁頭,最多有256…

    Linux干貨 2016-08-30
  • Linux bash中的命令行展開介紹及應用示例

    Linux bash中的命令行展開介紹及應用示例 在Linux bash中可以使用命令行展開特性一步完成需要分開成多步完成的操作,達到事半功倍的效果。在Linux指令參數位置使用"{}" 將相應的參數括起來,括號中的參數以逗號分隔,然后bash在執行這一指令時會自動將括號中的內容進行展開。 相關示例如下: 同時創建多個目錄,在/tmp目錄…

    Linux干貨 2016-11-07
  • 常用RAID級別介紹

    RAID是什么         磁盤陣列(Redundant Arrays of Independent Disks,RAID),磁盤陣列是將多個價格便宜的磁盤按照一定的組合方式組成具有高容量的磁盤組,按照不同的組合方式可以達到不同的效果,如:可以提升磁盤的存取效率,可提高磁盤的…

    Linux干貨 2016-02-14
  • linux運維

    linux運維大綱,學習路線圖

    Linux干貨 2017-10-21
  • bash通配符和正則表達式元字符部分歸納

    Linux中有各種各樣的字符,而且在不同環境和不同命令之下含義也不同 作為新手,決定先歸納學到的符號,方便后面學習厘清它們之間的關系。 glob 簡化了的正則表達式 bash默認通配符: ? :只匹配一個任意字符; * :匹配零個或多個任意字符;   [^] :方括號及其中^中的取反 [abc]:匹配任何一個列在方括號中的字符(這個例子要么匹配一個…

    Linux干貨 2016-04-11

評論列表(2條)

  • 馬哥教育
    馬哥教育 2016-08-22 13:50

    總結的很好,態度很端正,加油。

    • M20-1鐘明波
      M20-1鐘明波 2016-08-23 22:56

      @馬哥教育好的,謝謝

欧美性久久久久