《9個函數(shù)示例,讓你重新認(rèn)識Shell》要點(diǎn):
本文介紹了9個函數(shù)示例,讓你重新認(rèn)識Shell,希望對您有用。如果有疑問,可以聯(lián)系我們。
拷貝文件時,測試目錄是否存在是常見的工作之一.以下函數(shù)測試傳遞給函數(shù)的文件名是否是一個目錄.因為此函數(shù)返回時帶有成功或失敗取值,可用if語句測試結(jié)果.函數(shù)如下:
is_it_a_directory()
{
? ? ? ?# is_it_a_directory
? ? ? ?# to call: is_it_a_directory directory_name
? ? ? ?if [ $# -lt 1 ]; then
? ? ? ? ? ? ? ?echo "is_it_a_directory: I need an argument"
? ? ? ? ? ? ? ?return 1
? ? ? ?fi ? ? ?
? ? ? ?# is it a directory ?
? ? ? ?_DIRECTORY_NAME=$1
? ? ? ?if [ ! -d $_DIRECTORY_NAME ]; then
? ? ? ? ? ? ? ?# no it is not
? ? ? ? ? ? ? ?return 1
? ? ? ?else ? ?
? ? ? ? ? ? ? ?# yes it is
? ? ? ? ? ? ? ?return 0
? ? ? ?fi ? ? ?
}
要調(diào)用函數(shù)并測試結(jié)果,可以使用:
echo -n "Enter destination directory :"
read DIREC
if is_it_a_directory $dires;
then : ?
else ? ?
? ? ? ?echo "$DIREC does no exist, create it now ? [y..]"
? ? ? ?# commands go here to either create the directory or exit
? ? ? ?...
? ? ? ?...
fi
許多腳本在繼續(xù)處理前會發(fā)出提示.大約可以提示以下動作:
? 創(chuàng)建一個目錄.
? 是否刪除文件.
? 是否后臺運(yùn)行.
? 確認(rèn)保存記錄.
等等
以下函數(shù)是一個真正的提示函數(shù),提供了顯示信息及缺省回答方式.缺省回答即用戶按下回車鍵時采取的動作.case語句用于捕獲回答:
continue_prompt()
# continue_prompt
# to call: continue_prompt "string to display" default_answer
{
? ? ? ?_STR=$1
? ? ? ?_DEFAULT=$2
? ? ? ?# check we have the right params
? ? ? ?if [ $# -lt 1 ]; then
? ? ? ? ? ? ? ?echo "continue_prompt: I need a string to display"
? ? ? ? ? ? ? ?return 1
? ? ? ?fi ? ? ?
? ? ? ?# loop forever
? ? ? ?while :
? ? ? ?do ? ? ?
? ? ? ? ? ? ? ?echo -n "$_STR [Y..N] [$_DEFAULT]:"
? ? ? ? ? ? ? ?read _ANS
? ? ? ? ? ? ? ?# if user hits return set the default and determine the return
? ? ? ? ? ? ? ?# value, that's s: then a <space> then $
? ? ? ? ? ? ? ?: ${_ANS:=$_DEFAULT}
? ? ? ? ? ? ? ?if [ "$_ANS" == "" ]; then
? ? ? ? ? ? ? ? ? ? ? ?case $_ANS in
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Y) return 0;;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?N) return 1;;
? ? ? ? ? ? ? ? ? ? ? ?esac ? ?
? ? ? ? ? ? ? ?fi ? ? ?
? ? ? ? ? ? ? ?# user has selected something
? ? ? ? ? ? ? ?case $_ANS in
? ? ? ? ? ? ? ? ? ? ? ?y|Y|Yes|YES) return 0
? ? ? ? ? ? ? ? ? ? ? ?;;
? ? ? ? ? ? ? ? ? ? ? ?n|N|No|NO) return 1
? ? ? ? ? ? ? ? ? ? ? ?;;
? ? ? ? ? ? ? ? ? ? ? ?*) echo "Answer either Y or N, default is $_DEFAULT"
? ? ? ? ? ? ? ? ? ? ? ?;;
? ? ? ? ? ? ? ?esac ? ?
? ? ? ? ? ? ? ?echo $_ANS
? ? ? ?done ? ?
}
要調(diào)用上述函數(shù),須給出顯示信息或參數(shù)$1,或字符串變量.缺省回答Y或N方式也必須指定.以下是幾種函數(shù)continueprompt的調(diào)用格式
if continue_prompt "Do you want to delete the var filesystem" "N"; then
? ? ? ?echo "Are you nuts!!"
else ? ?
? ? ? ?echo "Phew ! what a good answer"
fi
在腳本中加入上述語句,給出下列輸入:
Do you want to delete the var filesystem [Y..N] [N]:
Phew ! what a good answer
Do you want to delete the var filesystem [Y..N] [N]:y
Are you nuts!!
以下是函數(shù)調(diào)用的另一種方式:
if continue_prompt "Do you really want to print this report" "Y"; then
? ? ? ?lpr report
else :
fi
也可以使用字符串變量$1調(diào)用此函數(shù):
if continue_prompt $1 "Y"; then
? ? ? ?lpr report
else: ?
fi
當(dāng)所在系統(tǒng)很龐大,要和一登錄用戶通信時,如果忘了用戶的全名,這是很討厭的事.比如有時你看到用戶鎖住了一個進(jìn)程,但是它們的用戶ID號對你來說沒有意義,因此必須要用grep passwd文件以取得用戶全名,然后從中抽取可用信息,向其發(fā)信號,讓其他用戶開鎖.以下函數(shù)用于從grep /etc/passwd命令抽取用戶全名.本系統(tǒng)用戶全名位于passwd文件域5中,用戶的系統(tǒng)可能不是這樣,這時必須改變其域號以匹配passwd文件.這個函數(shù)需要一個或多個用戶ID號作為參數(shù).它對密碼文件進(jìn)行g(shù)rep操作.函數(shù)腳本如下:
whois()
# whois
# to call: whois userid
{
? ? ? ?# check we have the right params
? ? ? ?if [ $# -lt 1 ]; then
? ? ? ? ? ? ? ?echo "whois : need user id's pleas"
? ? ? ? ? ? ? ?return 1
? ? ? ?fi ? ? ?
? ? ? ?for loop
? ? ? ?do ? ? ?
? ? ? ? ? ? ? ?_USER_NAME=`grep $loop /etc/passwd | awk -F: '{print $4}'`
? ? ? ? ? ? ? ?if [ "$_USER_NAME" == "" ]; then
? ? ? ? ? ? ? ? ? ? ? ?echo "whois: Sorry cannot find $loop"
? ? ? ? ? ? ? ?else ? ?
? ? ? ? ? ? ? ? ? ? ? ?echo "$loop is $_USER_NAME"
? ? ? ? ? ? ? ?fi ? ? ?
? ? ? ?done ? ?
}
在vi編輯器中,可以列出行號來進(jìn)行調(diào)試,但是如果打印幾個帶有行號的文件,必須使用nl命令.以下函數(shù)用nl命令列出文件行號.原始文件中并不帶有行號.
# number_file
# to call: number_file filename
number_file()
{
? ? ? ?_FILENAME=$1
? ? ? ?# check we have the right params
? ? ? ?if [ $# -ne 1 ]; then
? ? ? ? ? ? ? ?echo "number_file: I need a filename to number"
? ? ? ? ? ? ? ?return 1
? ? ? ?fi ? ? ?
? ? ? ?loop=1
? ? ? ?while read LINE[quote]
? ? ? ?do ? ? ?
? ? ? ? ? ? ? ?echo "$loop: $LINE"
? ? ? ? ? ? ? ?loop=`expr $loop + 1`
? ? ? ?done < $_FILENAME
}
要調(diào)用numberfile函數(shù),可用一個文件名做參數(shù),或在shell中提供一文件名,例如:
$ number_file myfile
也可以在腳本中這樣寫或用:
number_file $1
在Linux中寫一個bash腳本,然后在腳本中定義函數(shù).同時使用number_file $1的方式調(diào)用該函數(shù),代碼如下:
#!/bin/bash
# number_file
# to call: number_file filename
number_file()
{
? ? ? ?_FILENAME=$1
? ? ? ?# check we have the right params
? ? ? ?if [ $# -ne 1 ]; then
? ? ? ? ? ? ? ?echo "number_file: I need a filename to number"
? ? ? ? ? ? ? ?return 1
? ? ? ?fi
? ? ? ?loop=1
? ? ? ?while read LINE
? ? ? ?do
? ? ? ? ? ? ? ?echo "$loop: $LINE"
? ? ? ? ? ? ? ?loop=`expr $loop + 1`
? ? ? ?done < $_FILENAME
}
number_file $1
執(zhí)行腳本輸出如下:
1: 10.0.0.1 dev ppp0 ?proto kernel ?scope link ?src 192.168.100.7
2: 10.0.0.1 dev ppp1 ?proto kernel ?scope link ?src 192.168.100.8
3: 88.88.88.0/24 dev eth0 ?proto kernel ?scope link ?src 88.88.88.210
4: 127.0.0.0/24 dev lo ?scope link
5: default
6: nexthop dev ppp0 weight 1
7: nexthop dev ppp1 weight 1
8:
直接用nl的輸出結(jié)果如下,對比兩者,似乎前者更加直觀:
? ? 1 ?10.0.0.1 dev ppp0 ?proto kernel ?scope link ?src 192.168.100.7
? ? 2 ?10.0.0.1 dev ppp1 ?proto kernel ?scope link ?src 192.168.100.8
? ? 3 ?88.88.88.0/24 dev eth0 ?proto kernel ?scope link ?src 88.88.88.210
? ? 4 ?127.0.0.0/24 dev lo ?scope link
? ? 5 ?default
? ? 6 ? ? ? ? ?nexthop dev ppp0 weight 1
? ? 7 ? ? ? ? ? ? ? ? ?nexthop dev ppp1 weight 1
有時需要在文件中將字符串轉(zhuǎn)為大寫,例如在文件系統(tǒng)中只用大寫字符創(chuàng)建目錄或在有效的文本域中將輸入轉(zhuǎn)換為大寫數(shù)據(jù).以下是相應(yīng)功能函數(shù),可以想像要用到tr命令:
#/bin/bash
# str_to_upper
# to call: str_to_upper $1
str_to_upper()
{
? ? ? ?_STR=$1
? ? ? ?# check we have the right params
? ? ? ?if [ $# -ne 1 ]; then
? ? ? ? ? ? ? ?echo "number_file: I need a string to convert please"
? ? ? ? ? ? ? ?return 1
? ? ? ?fi ? ? ?
? ? ? ?echo $@ | tr '[a-z]' '[A-Z]'
}
str_to_upper $1
變量upper 保存返回的大寫字符串,注意這里用到特定參數(shù)$@來傳遞所有參數(shù).strtoupper可以以兩種方式調(diào)用.在腳本中可以這樣指定字符串.
UPPER=`sh str_to_upper.sh filename`
echo $UPPER
或者以函數(shù)輸入?yún)?shù)$1的形式調(diào)用它:
UPPER=`sh str_to_upper.sh $1`
echo $UPPER
雖然函數(shù)strtoupper做字符串轉(zhuǎn)換,但有時在進(jìn)一步處理前只需知道字符串是否為大寫.isupper實現(xiàn)此功能.在腳本中使用if語句決定傳遞的字符串是否為大寫.函數(shù)如下:
is_upper()
{
? ? ? ?# check we have the right params
? ? ? ?if [ $# -ne 1 ]; then
? ? ? ? ? ? ? ?echo "is_upper: I need a string to test OK"
? ? ? ? ? ? ? ?return 1
? ? ? ?fi ? ? ?
? ? ? ?# use awk to check we have only upper case
? ? ? ?_IS_UPPER=`echo $1 | awk '{if($0~/[^A-Z]/) print "1"}'`
? ? ? ?if [ "$_IS_UPPER" != "" ]; then
? ? ? ? ? ? ? ?# no, they are not all upper case
? ? ? ? ? ? ? ?return 1
? ? ? ?else ? ?
? ? ? ? ? ? ? ?# yes all upper case
? ? ? ? ? ? ? ?return 0
? ? ? ?fi ? ? ?
}
要調(diào)用isupper,只需給出字符串參數(shù).以下為其調(diào)用方式:
echo -n "Enter the filename :"
read FILENAME
if is_upper $FILENAME; then
? ? ? ?echo "Great it's upper case"
? ? ? ?# let's create a file maybe ??
else ? ?
? ? ? ?echo "Sorry it's not upper case"
? ? ? ?# shall we convert it anyway using str_to_upper ???
fi
要測試字符串是否為小寫,只需在函數(shù)is_upper中替換相應(yīng)的awk語句即可.此為islower.
_IS_LOWER=`echo $1 | awk '{if($0~/[^a-z]/) print "1"}'`
在腳本中確認(rèn)域輸入有效是常見的任務(wù)之一.確認(rèn)有效包括許多方式,如輸入是否為數(shù)字或字符;域的格式與長度是否為確定形式或值.假定腳本要求用戶交互輸入數(shù)據(jù)到名稱域,你會想控制此域包含字符數(shù)目,比如人名最多為20個字符.有可能用戶輸入超過50個字符.以下函數(shù)實施控制功能.需要向函數(shù)傳遞兩個參數(shù),實際字符串和字符串最大長度.函數(shù)如下:
check_length()
# check length
# to call: check_length string max_length_of_string
{
? ? ? ?_STR=$1
? ? ? ?_MAX=$2
? ? ? ?# check we have the right params
? ? ? ?if [ $# -ne 2 ]; then
? ? ? ? ? ? ? ?echo "check_length: I need a string and max length the string sh
oudle be"
? ? ? ? ? ? ? ?return 1
? ? ? ?fi ? ? ?
? ? ? ?# check the length of the string
? ? ? ?_LENGTH=`echo $_STR | awk '{print length($0)}'`
? ? ? ?if [ "$_LENGTH" -gt "$_MAX" ]; then
? ? ? ? ? ? ? ?# length of string is too big
? ? ? ? ? ? ? ?return 1
? ? ? ?else ? ?
? ? ? ? ? ? ? ?# string is ok in length
? ? ? ? ? ? ? ?return 0
? ? ? ?fi ? ?
}
調(diào)用函數(shù)checklength:
while :
do
? ? ? ?echo -n "Enter your FIRST name :"
? ? ? ?read NAME
? ? ? ?if check_length $NAME 10
? ? ? ?then
? ? ? ? ? ? ? ?break
? ? ? ? ? ? ? ?# do nothing fall through condition all is ok
? ? ? ?else
? ? ? ? ? ? ? ?echo "The name field is too long 10 characters max"
? ? ? ?fi
done
循環(huán)持續(xù)直到輸入到變量NAME的數(shù)據(jù)小于最大字符長度,這里指定為10,break命令然后跳出循環(huán).使用上述腳本段,輸出結(jié)果如下:
Enter your FIRST name :Perterrrrrrrrrrrrrrrrrrrrrrrrrr
The name field is too long 10 characters max
Enter your FIRST name :Peter
可以使用wc命令取得字符串長度.但是要注意,使用wc命令接受鍵盤輸入時有一個誤操作.如果用戶輸入了一個名字后,點(diǎn)擊了幾次空格鍵, wc會將這些空格也作為字符串的一部分,因而給出其錯誤長度.awk在讀取鍵盤時缺省截去字符串末尾處空格.以下是wc命令的缺點(diǎn)舉例(也可以稱為特征之一)
#!/bin/bash
echo -n "name :"
read NAME
echo $NAME | wc -c
運(yùn)行上述腳本(其中?為空格)
name eter??
6
要在腳本中調(diào)用函數(shù),首先創(chuàng)建函數(shù),并確保它位于調(diào)用之前.以下腳本使用了兩個函數(shù).此腳本前面提到過,它用于測試目錄是否存在.
#!/bin/sh
# function file
is_it_a_directory()
{
? ? ? ?# is_it_a_directory
? ? ? ?# to call: is_it_a_directory directory_name
? ? ? ?_DIRECTORY_NAME=$1
? ? ? ?if [ $# -lt 1 ]; then
? ? ? ? ? ? ? ?echo "is_it_a_directory: I need a directory name to check"
? ? ? ? ? ? ? ?return 1
? ? ? ?fi ? ? ?
? ? ? ?# is it a directory ?
? ? ? ?if [ ! -d $_DIRECTORY_NAME ]; then
? ? ? ? ? ? ? ?return 1
? ? ? ?else ? ?
? ? ? ? ? ? ? ?return 0
? ? ? ?fi ? ? ?
}
# --------------------------------------------
error_msg()
{
? ? ? ?# error_msg
? ? ? ?# beeps: display messages; beeps again!
? ? ? ?echo -e "\007"
? ? ? ?echo $@
? ? ? ?echo -e "\007"
? ? ? ?return 0
}
### END OF FUNCTIONS
echo -n "Enter destination directory :"
read DIREC
if is_it_a_directory $DIREC
then :
else ? ?
? ? ? ?error_msg "$DIREC does not exist...creating it now"
? ? ? ?mkdir $DIREC > /dev/null 2>&1
? ? ? ?if [ $? != 0 ]; then
? ? ? ? ? ? ? ?error_msg "Could not create directory:: check it out!"
? ? ? ? ? ? ? ?exit 1
? ? ? ?else :
? ? ? ?fi ? ? ?
fi ? ? ?
# not a directory
echo "extracting files ..."
上述腳本中,兩個函數(shù)定義于腳本開始部分,并在腳本主體中調(diào)用.所有函數(shù)都應(yīng)該在任何腳本主體前定義.注意錯誤信息語句,這里使用函數(shù)errormsg顯示錯誤,反饋所有傳遞到該函數(shù)的參數(shù),并加兩聲警報.
前面講述了怎樣在命令行中調(diào)用函數(shù),這類函數(shù)通常用于系統(tǒng)報表功能.現(xiàn)在再次使用上面的函數(shù),但是這次將之放入函數(shù)文件functions.sh里.sh意即shell腳本
#!/bin/sh
# functions.sh
# main scripts functions
is_it_a_directory()
{
? ? ? ?# is_it_a_directory
? ? ? ?# to call: is_it_a_directory directory_name
? ? ? ?_DIRECTORY_NAME=$1
? ? ? ?if [ $# -lt 1 ]; then
? ? ? ? ? ? ? ?echo "is_it_a_directory: I need a directory name to check"
? ? ? ? ? ? ? ?return 1
? ? ? ?fi ? ? ?
? ? ? ?# is it a directory ?
? ? ? ?if [ ! -d $_DIRECTORY_NAME ]; then
? ? ? ? ? ? ? ?return 1
? ? ? ?else ? ?
? ? ? ? ? ? ? ?return 0
? ? ? ?fi ? ? ?
}
# --------------------------------------------
error_msg()
{
? ? ? ?# error_msg
? ? ? ?# beeps: display messages; beeps again!
? ? ? ?echo -e "\007"
? ? ? ?echo $@
? ? ? ?echo -e "\007"
? ? ? ?return 0
}
現(xiàn)在編寫腳本就可以調(diào)用functions.sh中的函數(shù)了.注意函數(shù)文件在腳本中以下述命令格式定位:
. <path to file>
使用這種方法不會創(chuàng)建另一個shell,所有函數(shù)均在當(dāng)前shell下執(zhí)行.
#!/bin/sh
# direc_check
# source the funtion file fuctions.sh
# that's a <dot><space><forward slash>
. ./functions.sh
# now we can use the fuctions(s)
echo -n "Enter destination directory :"
read DIREC ? ? ? ? ? ? ? ? ? ? ?
if is_it_a_directory $DIREC
then : ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
else ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ?error_msg "$DIREC does not exist ... creating it now!" ? ? ? ? ?
? ? ? ?mkdir $DIREC > /dev/null 2>&1
? ? ? ?if [ $? != 0 ]; then ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ?error_msg "Could not create directory:: check it out!"
? ? ? ? ? ? ? ?exit 1
? ? ? ?else : ?
? ? ? ?fi
fi ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
# not a directory
echo "extracting files ..."
執(zhí)行結(jié)果如下所示:
# sh direc_check.sh Enter destination directory :AUDIT AUDIT does not exist...creating it now extracting files ...
文:馬哥Linux團(tuán)隊
文章出處:運(yùn)維部落
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.snjht.com/jiaocheng/4473.html