日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux Shell常用技巧(十二)

發(fā)布時(shí)間:2024/4/15 linux 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux Shell常用技巧(十二) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

二十三. Bash Shell編程:

?? ?1.? 讀取用戶變量:
?? ?read命令是用于從終端或者文件中讀取輸入的內(nèi)建命令,read命令讀取整行輸入,每行末尾的換行符不被讀入。在read命令后面,如果沒(méi)有指定變量名,讀取的數(shù)據(jù)將被自動(dòng)賦值給特定的變量REPLY。下面的列表給出了read命令的常用方式:

命令格式描述
read answer從標(biāo)準(zhǔn)輸入讀取輸入并賦值給變量answer。
read first last從標(biāo)準(zhǔn)輸入讀取輸入到第一個(gè)空格或者回車,將輸入的第一個(gè)單詞放到變量first中,并將該行其他的輸入放在變量last中。
read從標(biāo)準(zhǔn)輸入讀取一行并賦值給特定變量REPLY。
read -a arrayname把單詞清單讀入arrayname的數(shù)組里。
read -p prompt打印提示,等待輸入,并將輸入存儲(chǔ)在REPLY中。
read -r line允許輸入包含反斜杠。


??? 見(jiàn)下面的示例(綠色高亮部分的文本為控制臺(tái)手工輸入信息):
??? /> read answer?? ??? ?#等待讀取輸入,直到回車后表示輸入完畢,并將輸入賦值給變量answer
??? Hello?? ??? ??? ??? ??????? #控制臺(tái)輸入Hello
??? /> echo $answer?? ?? #打印變量
?? ?Hello

?? ?#等待一組輸入,每個(gè)單詞之間使用空格隔開(kāi),直到回車結(jié)束,并分別將單詞依次賦值給這三個(gè)讀入變量。
??? /> read one two three
??? 1 2 3?? ??? ??? ??? ?????? #在控制臺(tái)輸入1 2 3,它們之間用空格隔開(kāi)。
??? /> echo "one = $one, two = $two, three = $three"
?? ?one = 1, two = 2, three = 3

??? /> read?? ??? ??? ??? ?? #等待控制臺(tái)輸入,并將結(jié)果賦值給特定內(nèi)置變量REPLY。
??? This is REPLY?? ??? ?? #在控制臺(tái)輸入該行。
??? /> echo $REPLY?? ?? #打印輸出特定內(nèi)置變量REPLY,以確認(rèn)是否被正確賦值。
?? ?This is REPLY

??? /> read -p "Enter your name: "?? ?#輸出"Enter your name: "文本提示,同時(shí)等待輸入,并將結(jié)果賦值給REPLY。
?? ?Enter you name: stephen?? ??? ??? ?#在提示文本之后輸入stephen
??? /> echo $REPLY
?? ?stephen

?? ?#等待控制臺(tái)輸入,并將輸入信息視為數(shù)組,賦值給數(shù)組變量friends,輸入信息用空格隔開(kāi)數(shù)組的每個(gè)元素
??? /> read -a friends
??? Tim Tom Helen
??? /> echo "I have ${#friends} friends"
?? ?I have 3 friends
??? /> echo "They are ${friends[0]}, ${friends[1]} and ${friends[2]}."
?? ?They are Tim, Tom and Helen.

?? 2.? 狀態(tài)判斷:
?? ?test是Shell中提供的內(nèi)置命令,主要用于狀態(tài)的檢驗(yàn),如果結(jié)果為0,表示成功,否則表示失敗。見(jiàn)如下示例:
?? ?/> name=stephen
?? ?/> test $name != stephen
?? ?/> echo $?
?? ?1
?? ?需要注意的是test命令不支持Shell中提供的各種通配符,如:
?? ?/> test $name = [Ss]tephen
?? ?/> echo $?
?? ?1
?? ?test命令還可以中括號(hào)予以替換,其語(yǔ)義保持不變,如:
?? ?/> [ $name = stephen ]
?? ?/> echo $?
?? ?0???
?? ?在Shell中還提供了另外一種用于狀態(tài)判斷的方式:[[ expr ]],和test不同的是,該方式中的表達(dá)式支持通配符,如:
?? ?/> name=stephen
?? ?/> [[ $name == [Ss]tephen ]]
?? ?/> echo $?
?? ?0
?? ?#在[[ expression ]]中,expression可以包含&&(邏輯與)和||(邏輯或)。
?? ?/> [[ $name == [Ss]tephen && $friend == "Jose" ]]
?? ?/> echo $?
?? ?1
??? /> shopt -s extglob?? #打開(kāi)Shell的擴(kuò)展匹配模式。
?? ?/> name=Tommy
?? ?# "[Tt]o+(m)y"的含義為,以T或t開(kāi)頭,后面跟著一個(gè)o,再跟著一個(gè)或者多個(gè)m,最后以一個(gè)y結(jié)尾。
??? /> [[ $name == [Tt]o+(m)y ]]
?? ?/> echo $?
?? ?0
?? ?在Shell中還提供了let命令的判斷方式: (( expr )),該方式的expr部分,和C語(yǔ)言提供的表達(dá)式規(guī)則一致,如:
?? ?/> x=2
?? ?/> y=3
?? ?/> (( x > 2 ))
?? ?/> echo $?
?? ?1
?? ?/> (( x < 2 ))
?? ?/> echo $?
?? ?0  
?? ?/> (( x == 2 && y == 3 ))
?? ?/> echo $?
?? ?0
?? ?/> (( x > 2 || y < 3 ))
?? ?/> echo $?
?? ?1

??? 下面的表格是test命令支持的操作符:

判斷操作符判斷為真的條件
字符串判斷?
[ stringA=stringB ]stringA等于stringB
[ stringA==stringB ]stringA等于stringB
[ stringA!=stringB ]stringA不等于stringB
[ string ]string不為空
[ -z string ]string長(zhǎng)度為0
[ -n string ]string長(zhǎng)度不為0
邏輯判斷?
[ stringA -a stringB ]stringA和stringB都是真
[ stringA -o stringB ]stringA或stringB是真
[ !string ]string不為真
邏輯判斷(復(fù)合判斷)?
[[ pattern1 && pattern2 ]]pattern1和pattern2都是真
[[ pattern1 || pattern2 ]pattern1或pattern2是真
[[ !pattern ]]pattern不為真
整數(shù)判斷?
[ intA -eq intB ]intA等于intB
[ intA -ne intB ]intA不等于intB
[ intA -gt intB ]intA大于intB
[ intA -ge intB ]intA大于等于intB
[ intA -lt intB ]intA小于intB
[ intA -le intB ]intA小于等于intB
文件判斷中的二進(jìn)制操作?
[ fileA -nt fileB ]fileA比f(wàn)ileB新
[ fileA -ot fileB ]fileA比f(wàn)ileB舊
[ fileA -ef fileB ]fileA和fileB有相同的設(shè)備或者inode值
文件檢驗(yàn)?
[ -d $file ] or [[ -d $file ]]file為目錄且存在時(shí)為真
[ -e $file ] or [[ -e $file ]]file為文件且存在時(shí)為真
[ -f $file ] or [[ -f $file ]]file為非目錄普通文件存在時(shí)為真
[ -s $file ] or [[ -s $file ]]file文件存在, 且長(zhǎng)度不為0時(shí)為真
[ -L $file ] or [[ -L $file ]]file為鏈接符且存在時(shí)為真
[ -r $file ] or [[ -r $file ]]file文件存在且可讀時(shí)為真
[ -w $file ] or [[ -w $file ]]file文件存在且可寫(xiě)時(shí)為真
[ -x $file ] or [[ -x $file ]]file文件存在且可執(zhí)行時(shí)為真

??? 注:在邏輯判斷(復(fù)合判讀中),pattern可以包含元字符,在字符串的判斷中,pattern2必須被包含在引號(hào)中。

?? ?let命令支持的操作符和C語(yǔ)言中支持的操作符完全相同,如:
?? ?+,-,*,/,%??????????? 加,減,乘,除,去模
?? ?>>,<<?? ??? ???????? 右移和左移
?? ?>=,<=,==,!=?? ?? 大于等于,小于等于,等于,不等于
?? ?&,|,^?? ??? ?????????? 按位與,或,非
?? ?&&,||,!?? ??? ? ? ???? 邏輯與,邏輯或和取反
?? ?還有其含義和C語(yǔ)言等同的快捷操作符,如=,*=,/=,%=,+=,-=,<<=,>>=,&=,|=,^=。

??? 3.? 流程控制語(yǔ)句:
??? if語(yǔ)句格式如下:
?? ?#if語(yǔ)句的后面是Shell命令,如果該命令執(zhí)行成功返回0,則執(zhí)行then后面的命令。
?? ?if command?? ??? ?
?? ?then
?? ??? ?command
?? ??? ?command
?? ?fi
?? ?#用test命令測(cè)試其后面expression的結(jié)果,如果為真,則執(zhí)行then后面的命令。
?? ?if test expression
?? ?then
?? ??? ?command
?? ?fi
?? ?#下面的格式和test expression等同
?? ?if [ string/numeric expression ]
?? ?then
?? ??? ?command
?? ?fi
?? ?#下面的兩種格式也可以用于判斷語(yǔ)句的條件表達(dá)式,而且它們也是目前比較常用的兩種。
?? ?if [[ string expression ]]
?? ?then
?? ??? ?command
?? ?fi

??? if (( numeric expression ))?????????? #let表達(dá)式
?? ?then
?? ??? ?command
?? ?fi
?? ?見(jiàn)如下示例:
??? /> cat > test1.sh? ??? ??? ??? ??? ??? ?#從命令行直接編輯test1.sh文件。
?? ?echo -e "Are you OK(y/n)? \c"
?? ?read answer
??? #這里的$answer變量必須要用雙引號(hào)擴(kuò)住,否則判斷將失敗。當(dāng)變量$answer等于y或Y時(shí),支持下面的echo命令。
?? ?if [ "$answer" = y -o "$answer" = Y ]? ?
?? ?then
?? ???? echo "Glad to see it."
?? ?fi
?? ?CTRL+D ?
??? /> . ./test1.sh
?? ?Are you OK(y/n)? y
?? ?Glad to see it.
?? ?上面的判斷還可以替換為:
??? /> cat > test2.sh
?? ?echo -e "Are you OK(y/n or Maybe)? \c"
?? ?read answer
?? ?# [[ ]]復(fù)合命令操作符允許其中的表達(dá)式包含元字符,這里輸入以y或Y開(kāi)頭的任意單詞,或Maybe都執(zhí)行then后面的echo。
?? ?if [[ $answer == [yY]* || $answer = Maybe ]] ?
?? ?then
?? ??? ?echo "Glad to hear it.
?? ?fi
?? ?CTRL+D
?? ?/> . ./test2.sh
?? ?Are you OK(y/n or Maybe)? yes
?? ?Glad to hear it.
?? ?下面的例子將使用Shell中的擴(kuò)展通配模式。
??? /> shopt -s extglob?? ??? ?#打開(kāi)該擴(kuò)展模式
??? /> answer="not really"
?? ?/> if [[ $answer = [Nn]o?( way |t really) ]]
?? ?> then
?? ?>?? ?echo "I am sorry."
?? ?> fi
?? ?I am sorry.
??? 對(duì)于本示例中的擴(kuò)展通配符,這里需要給出一個(gè)具體的解釋。[Nn]o匹配No或no,?( way|t really)則表示0個(gè)或1個(gè)( way或t really),因此answer變量匹配的字符串為No、no、Not really、not really、No way、no way。
??? 下面的示例使用了let命令操作符,如:
??? /> cat > test3.sh
?? ?if (( $# != 2 ))??????????????????? #等同于 [ $# -ne 2 ]
??? then
?? ???? echo "Usage: $0 arg1 arg2" 1>&2
?? ???? exit 1?? ??? ??? ??? ??? ????? #exit退出值為0-255之間,只有0表示成功。
??? fi
?? ?if (( $1 < 0 || $1 > 30 ))????? #等同于 [ $1 -lt 0 -o $1 -gt 30 ]
??? then
?? ???? echo "arg1 is out of range."
?? ???? exit 2
?? ?fi
?? ?if (( $2 <= 20 ))??????????????? ? #等同于 [ $2 -le 20 ]
??? then
?? ???? echo "arg2 is out of range."
?? ?fi
?? ?CTRL+D
?? ?/> sh ./test3.sh
?? ?Usage: ./test3.sh arg1 arg2
??? /> echo $??? ??? ??? ??? ??? ??? ?? #Shell腳本的退出值為exit的參數(shù)值。
?? ?1
??? /> sh ./test3.sh 40 30
?? ?arg1 is out of range.
??? /> echo $?
?? ?2
??? 下面的示例為如何在if的條件表達(dá)式中檢驗(yàn)空變量:
??? /> cat > test4.sh
?? ?if [ "$name" = "" ]??????????????? #雙引號(hào)就表示空字符串。
?? ?then
?? ??? ?echo "name is null."
?? ?fi
?? ?CTRL+D
?? ?/> . ./test4.sh
?? ?name is null.

??? if/elif/else語(yǔ)句的使用方式和if語(yǔ)句極為相似,相信有編程經(jīng)驗(yàn)的人都不會(huì)陌生,這里就不在贅述了,其格式如下:
?? ?if command
?? ?then
?? ??? ?command
?? ?elif command
?? ?then
?? ??? ?command
?? ?else
?? ??? ?command
?? ?fi
?? ?見(jiàn)如下示例腳本:
??? /> cat > test5.sh
?? ?echo -e "How old are you? \c"
?? ?read age
?? ?if [ $age -lt 0 -o $age -gt 120 ]???????? ? ?? ? #等同于 (( age < 0 || age > 120 ))
??? then
?? ???? echo "You are so old."
?? ?elif [ $age -ge 0 -a $age -le 12 ]?? ??? ??? ??? #等同于 (( age >= 0 && age <= 12 ))
??? then
?? ???? echo "You are child."
?? ?elif [ $age -ge 13 -a $age -le 19 ]?? ??? ??? ? #等同于 (( age >= 13 && age <= 19 ))
??? then
?? ???? echo "You are 13--19 years old."
?? ?elif [ $age -ge 20 -a $age -le 29 ]?? ??? ??? ? #等同于 (( age >= 20 && age <= 29 ))
??? then
?? ???? echo "You are 20--29 years old."
?? ?elif [ $age -ge 30 -a $age -le 39 ]?? ??? ??? ? #等同于 (( age >= 30 && age <= 39 ))
??? then
?? ???? echo "You are 30--39 years old."
?? ?else
?? ???? echo "You are above 40."
?? ?fi
?? ?CTRL+D
?? ?/> . ./test5.sh
?? ?How old are you? 50
?? ?You are above 40.

??? case語(yǔ)句格式如下:
? ? case variable in
?? ?value1)
?? ??? ?command
?? ??? ?;;?? ??? ??? ?#相同于C語(yǔ)言中case語(yǔ)句內(nèi)的break。
??? value2)
?? ??? ?command
?? ??? ?;;
?? ?*)?? ??? ??? ??? ?#相同于C語(yǔ)言中switch語(yǔ)句內(nèi)的default
? ??? ?command
?? ??? ?;;
?? ?esac
?? ?見(jiàn)如下示例腳本:
?? ?/> cat > test6.sh
?? ?#!/bin/sh
?? ?echo -n "Choose a color: "
?? ?read color
?? ?case "$color" in
?? ?[Bb]l??)
?? ???? echo "you select blue color."
??????? ;;
?? ?[Gg]ree*)
?? ???? echo "you select green color."
?? ???? ;;
?? ?red|orange)
?? ???? echo "you select red or orange."
?? ???? ;;
?? ?*)
?? ???? echo "you select other color."
?? ???? ;;
?? ?esac
?? ?echo "Out of case command."
?? ?/> . ./test6.sh
?? ?Choose a color: green
?? ?you select green color.
?? ?Out of case command.

? ?4.? 循環(huán)語(yǔ)句:
?? ?Bash Shell中主要提供了三種循環(huán)方式:for、while和until
??? for循環(huán)聲明格式:
?? ?for variable in word_list
?? ?do
?? ??? ?command
?? ?done
?? ?見(jiàn)如下示例腳本:
??? /> cat > test7.sh
?? ?for score in math english physics chemist?? #for將循環(huán)讀取in后面的單詞列表,類似于Java的for-each。
?? ?do
?? ??? ?echo "score = $score"
?? ?done
?? ?echo "out of for loop"
?? ?CTRL+D
??? /> . ./test7.sh
?? ?score = math
?? ?score = english
?? ?score = physics
?? ?score = chemist
?? ?out of for loop

??? /> cat > mylist?? #構(gòu)造數(shù)據(jù)文件
??? tom
?? ?patty
?? ?ann
?? ?jake
?? ?CTRL+D
??? /> cat > test8.sh
?? ?#!/bin/sh
?? ?for person in $(cat mylist)???????????????? #for將循環(huán)讀取cat mylist命令的執(zhí)行結(jié)果。
??? do
?? ???? echo "person = $person"
?? ?done
?? ?echo "out of for loop."
?? ?CTRL+D
?? ?/> . ./test8.sh
?? ?person = tom
?? ?person = patty
?? ?person = ann
?? ?person = jake
?? ?out of for loop.

??? /> cat > test9.sh
?? ?for file in test[1-8].sh??????????????????????? #for將讀取test1-test8,后綴為.sh的文件
??? do
?? ???? if [ -f $file ]?? ??? ??? ??? ??? ??? ?????? #判斷文件在當(dāng)前目錄是否存在。
??????? then
?? ? ? ? ?? echo "$file exists."
?? ???? fi
?? ?done
?? ?CTRL+D
?? ?/> . ./test9.sh
?? ?test2.sh exists.
?? ?test3.sh exists.
?? ?test4.sh exists.
?? ?test5.sh exists.
?? ?test6.sh exists.
?? ?test7.sh exists.
?? ?test8.sh exists.

??? /> cat > test10.sh
?? ?for name in $*?? ??? ??? ??? ??? ??? ??? ? ?? ? #讀取腳本的命令行參數(shù)數(shù)組,還可以寫(xiě)成for name的簡(jiǎn)化形式。
??? do
?? ???? echo "Hi, $name"
?? ?done
?? ?CTRL+D
?? ?/> . ./test10.sh stephen ann
?? ?Hi, stephen
?? ?Hi, ann

??? while循環(huán)聲明格式:
??? while command? #如果command命令的執(zhí)行結(jié)果為0,或條件判斷為真時(shí),執(zhí)行循環(huán)體內(nèi)的命令。
?? ?do
?? ??? ?command
?? ?done
?? ?見(jiàn)如下示例腳本:
??? /> cat > test1.sh??
??? num=0
?? ?while (( num < 10 ))?????????????? #等同于 [ $num -lt 10 ]
??? do
?? ???? echo -n "$num "
?? ???? let num+=1
?? ?done
?? ?echo -e "\nHere's out of loop."
?? ?CTRL+D
?? ?/> . ./test1.sh
?? ?0 1 2 3 4 5 6 7 8 9
?? ?Here's out of loop.

??? /> cat > test2.sh
?? ?go=start
?? ?echo Type q to quit.
?? ?while [[ -n $go ]]???????????????????? #等同于[ -n "$go" ],如使用該風(fēng)格,$go需要被雙引號(hào)括起。
??? do
?? ???? echo -n How are you.
?? ???? read word
?? ???? if [[ $word == [Qq] ]]????? #等同于[ "$word" = Q -o "$word" = q ]
??? ??? then
?? ???????? echo Bye.
?? ???????? go=?? ??? ??? ??? ???????? #將go變量的值置空。
??????? fi
?? ?done
?? ?CTRL+D
?? ?/> . ./test2.sh
?? ?How are you. Hi
?? ?How are you. q
?? ?Bye.

??? until循環(huán)聲明格式:
??? until command ? ? ? ? ? ? ? ? ? ? ? ? #其判斷條件和while正好相反,即command返回非0,或條件為假時(shí)執(zhí)行循環(huán)體內(nèi)的命令。
??? do
?? ??? ?command
?? ?done
?? ?見(jiàn)如下示例腳本:
??? /> cat > test3.sh
?? ?until who | grep stephen?????????? #循環(huán)體內(nèi)的命令將被執(zhí)行,直到stephen登錄,即grep命令的返回值為0時(shí)才退出循環(huán)。
??? do
?? ???? sleep 1
?? ???? echo "Stephen still doesn't login."
?? ?done
?? ?CTRL+D

??? shift命令聲明格式:
shift [n]
?? ?shift命令用來(lái)把腳本的位置參數(shù)列表向左移動(dòng)指定的位數(shù)(n),如果shift沒(méi)有參數(shù),則將參數(shù)列表向左移動(dòng)一位。一旦移位發(fā)生,被移出列表的參數(shù)就被永遠(yuǎn)刪除了。通常在while循環(huán)中,shift用來(lái)讀取列表中的參數(shù)變量。
?? ?見(jiàn)如下示例腳本:
??? /> set stephen ann sheryl mark #設(shè)置4個(gè)參數(shù)變量。
??? /> shift?? ??? ??? ??? ??? ??? ???????????? #向左移動(dòng)參數(shù)列表一次,將stephen移出參數(shù)列表。
??? /> echo $*
?? ?ann sheryl mark
??? /> shift 2?? ??? ??? ??? ??? ??? ????????? #繼續(xù)向左移動(dòng)兩位,將sheryl和ann移出參數(shù)列表
??? /> echo $*
?? ?mark
??? /> shift 2?? ??? ??? ??? ??? ??? ????????? #繼續(xù)向左移動(dòng)兩位,由于參數(shù)列表中只有mark了,因此本次移動(dòng)失敗。
??? /> echo $*
?? ?mark

??? /> cat > test4.sh
?? ?while (( $# > 0 ))?? ??? ??? ??? ???? #等同于 [ $# -gt 0 ]
??? do
?? ???? echo $*
?? ???? shift
?? ?done
?? ?CTRL+D
?? ?/> . ./test4.sh a b c d e
?? ?a b c d e
?? ?b c d e
?? ?c d e
?? ?d e
?? ?e?? ??? ?

??? break命令聲明格式:break [n]
?? ?和C語(yǔ)言不同的是,Shell中break命令攜帶一個(gè)參數(shù),即可以指定退出循環(huán)的層數(shù)。如果沒(méi)有指定,其行為和C語(yǔ)言一樣,即退出最內(nèi)層循環(huán)。如果指定循環(huán)的層數(shù),則退出指定層數(shù)的循環(huán)體。如果有3層嵌套循環(huán),其中最外層的為1,中間的為2,最里面的是3。
?? ?見(jiàn)如下示例腳本:
??? /> cat > test5.sh
?? ?while true
?? ?do
??????? echo -n "Are you ready to move on?"
??????? read answer
??????? if [[ $answer == [Yy] ]]
??????? then
??????????? break
??????? else
??????????? echo "Come on."
??????? fi
?? ?done
?? ?echo "Here we are."
?? ?CTRL+D
?? ?/> . ./test5.sh
?? ?Are you ready to move on? y
?? ?Here we are

??? continue命令聲明格式:continue [n]
?? ?和C語(yǔ)言不同的是,Shell中continue命令攜帶一個(gè)參數(shù),即可以跳轉(zhuǎn)到指定層級(jí)的循環(huán)頂部。如果沒(méi)有指定,其行為和C語(yǔ)言一樣,即跳轉(zhuǎn)到最內(nèi)層循環(huán)的頂部。如果指定循環(huán)的層數(shù),則跳轉(zhuǎn)到指定層級(jí)循環(huán)的頂部。如果有3層嵌套循環(huán),其中最外層的為3,中間的為2,最里面的是1。
??? /> cat? maillist?? ??? ??? ??? ? ? ? ? #測(cè)試數(shù)據(jù)文件maillist的內(nèi)容為以下信息。
?? ?stephen
?? ?ann
?? ?sheryl
?? ?mark

??? /> cat > test6.sh
?? ?for name in $(cat maillist)
?? ?do
?? ???? if [[ $name == stephen ]]; then
?? ???????? continue
?? ???? else
?? ???????? echo "Hello, $name."
?? ???? fi
?? ?done
?? ?CTRL+D
?? ?/> . ./test6.sh
?? ?Hello, ann.
?? ?Hello, sheryl.
?? ?Hello, mark.

??? I/O重新定向和子Shell:
?? ?文件中的輸入可以通過(guò)管道重新定向給一個(gè)循環(huán),輸出也可以通過(guò)管道重新定向給一個(gè)文件。Shell啟動(dòng)一個(gè)子Shell來(lái)處理I/O重新定向和管道。在循環(huán)終止時(shí),循環(huán)內(nèi)部定義的任何變量對(duì)于腳本的其他部分來(lái)說(shuō)都是不看見(jiàn)的。
??? /> cat > demodata?? ??? ??? ??? ??? ??? ?#為下面的腳本構(gòu)造冊(cè)數(shù)數(shù)據(jù)
?? ?abc
?? ?def
?? ?ghi
??? CRTL+D
??? /> cat > test7.sh
?? ?if (( $# < 1 ))?? ??? ??? ??? ??? ??? ??? ???? #如果腳本參數(shù)的數(shù)量小于1,則給出錯(cuò)誤提示后退出。
??? then
??????? echo "Usage: $0 filename " >&2
??????? exit 1
?? ?fi
?? ?count=1
?? ?cat $1 | while read line?? ??? ??? ??? ??? #參數(shù)一中的文件被cat命令輸出后,通過(guò)管道逐行輸出給while read line。
??? do
??????? let $((count == 1)) && echo "Processing file $1..." > /dev/tty? #該行的echo將輸出到當(dāng)前終端窗口。
??????? echo -e "$count\t$line"?? ??? ??? ?? #將輸出行號(hào)和文件中該行的內(nèi)容,中間用制表符隔開(kāi)。
??????? let count+=1
?? ?done > outfile?? ??? ??? ??? ??? ??? ??? ??? #將while循環(huán)中所有的輸出,除了>/dev/tty之外,其它的全部輸出到outfile文件。
??? CTRL+D
??? /> . ./test7.sh demodata?? ??? ??? ???? #只有一行輸出,其余的都輸出到outfile中了。
?? ?Processing file demodata...
??? /> cat outfile
?? ?1?????? abc
?? ?2?????? def
?? ?3?????? ghi

??? /> cat > test8.sh
?? ?for i in 9 7 2 3 5 4
?? ?do
?? ???? echo $i
?? ?done | sort -n?? ?? ? ?? ??? ??? ??? ??? ???? #直接將echo的輸出通過(guò)管道重定向sort命令。
?? ?CTRL+D
?? ?/> . ./test8.sh
?? ?2
?? ?3
?? ?4
?? ?5
?? ?7
?? ?9

??? 5.? IFS和循環(huán):
?? ?Shell的內(nèi)部域分隔符可以是空格、制表符和換行符。它可以作為命令的分隔符用在例如read、set和for等命令中。如果在列表中使用不同的分隔符,用戶可以自己定義這個(gè)符號(hào)。在修改之前將IFS原始符號(hào)的值保存在另外一個(gè)變量中,這樣在需要的時(shí)候還可以還原。
?? ?見(jiàn)如下示例腳本:
??? /> cat > test9.sh
?? ?names=Stephen:Ann:Sheryl:John?? #names變量包含的值用冒號(hào)分隔。
??? oldifs=$IFS?? ??? ??? ??? ??? ??? ??? ??? ??? #保留原有IFS到oldifs變量,便于后面的還原。
??? IFS=":"?? ??? ??? ??? ??? ??? ??? ?
?? ?for friends in $names?? ??? ??? ??? ??? ? #這是遍歷以冒號(hào)分隔的names變量值。?? ?
??? do
??????? echo Hi $friends
?? ?done
?? ?IFS=$oldifs?? ??? ??? ??? ??? ??? ??? ??? ??? #將IFS還原為原有的值。
??? set Jerry Tom Angela
?? ?for classmates in $*?? ??? ??? ??? ??? ?? #再以原有IFS的值變量參數(shù)列表。
??? do
??????? echo Hello $classmates
?? ?done
??? CTRL+D
?? ?/> . ./test9.sh
?? ?Hi Stephen
?? ?Hi Ann
?? ?Hi Sheryl
?? ?Hi John
?? ?Hello Jerry
?? ?Hello Tom
?? ?Hello Angela

??? 6.? 函數(shù):
?? ?Shell中函數(shù)的職能以及優(yōu)勢(shì)和C語(yǔ)言或其它開(kāi)發(fā)語(yǔ)言基本相同,只是語(yǔ)法格式上的一些差異。下面是Shell中使用函數(shù)的一些基本規(guī)則:
?? ?1) 函數(shù)在使用前必須定義。
?? ?2) 函數(shù)在當(dāng)前環(huán)境下運(yùn)行,它和調(diào)用它的腳本共享變量,并通過(guò)位置參量傳遞參數(shù)。而該位置參量將僅限于該函數(shù),不會(huì)影響到腳本的其它地方。
?? ?3) 通過(guò)local函數(shù)可以在函數(shù)內(nèi)建立本地變量,該變量在出了函數(shù)的作用域之后將不在有效。
?? ?4) 函數(shù)中調(diào)用exit,也將退出整個(gè)腳本。
?? ?5) 函數(shù)中的return命令返回函數(shù)中最后一個(gè)命令的退出狀態(tài)或給定的參數(shù)值,該參數(shù)值的范圍是0-256之間。如果沒(méi)有return命令,函數(shù)將返回最后一個(gè)Shell的退出值。
?? ?6) 如果函數(shù)保存在其它文件中,就必須通過(guò)source或dot命令把它們裝入當(dāng)前腳本。
?? ?7) 函數(shù)可以遞歸。
?? ?8) 將函數(shù)從Shell中清空需要執(zhí)行:unset -f function_name。
?? ?9) 將函數(shù)輸出到子Shell需要執(zhí)行:export -f function_name。
?? ?10) 可以像捕捉Shell命令的返回值一樣獲取函數(shù)的返回值,如$(function_name)。
?? ?Shell中函數(shù)的聲明格式如下:
??? function function_name { command; command; }
?? ?見(jiàn)如下示例腳本:
??? /> cat > test1.sh
?? ?function increment() {?? ??? ???? #定義函數(shù)increment。
??????? local sum?? ??? ??? ??? ??? ??????? #定義本地變量sum。
??????? let "sum=$1+1"?? ?
?? ???? return $sum?? ??? ??? ??? ??? ?? #返回值是sum的值。
??? }
?? ?echo -n "The num is "
?? ?increment 5?? ??? ??? ??? ??? ??? ?? #increment函數(shù)調(diào)用。
??? echo $??? ??? ??? ??? ??? ??? ??? ???? #輸出increment函數(shù)的返回值。
??? CTRL+D
?? ?/> . ./test1.sh
?? ?The num is 6

??? 7.? 陷阱信號(hào)(trap):
?? ?在Shell程序運(yùn)行的時(shí)候,可能收到各種信號(hào),有的來(lái)自于操作系統(tǒng),有的來(lái)自于鍵盤(pán),而該Shell在收到信號(hào)后就立刻終止運(yùn)行。但是在有些時(shí)候,你可能并不希望在信號(hào)到達(dá)時(shí),程序就立刻停止運(yùn)行并退出。而是他能希望忽略這個(gè)信號(hào)而一直在運(yùn)行,或者在退出前作一些清除操作。trap命令就允許你控制你的程序在收到信號(hào)以后的行為。
?? ?其格式如下:
?? ?trap 'command; command' signal-number
?? ?trap 'command; command' signal-name
?? ?trap signal-number ?
?? ?trap signal-name
?? ?后面的兩種形式主要用于信號(hào)復(fù)位,即恢復(fù)處理該信號(hào)的缺省行為。還需要說(shuō)明的是,如果trap后面的命令是使用單引號(hào)括起來(lái)的,那么該命令只有在捕獲到指定信號(hào)時(shí)才被執(zhí)行。如果是雙引號(hào),則是在trap設(shè)置時(shí)就可以執(zhí)行變量和命令替換了。
?? ?下面是系統(tǒng)給出的信號(hào)數(shù)字和信號(hào)名稱的對(duì)照表:
?? ?1)SIGHUP 2)SIGINT 3)SIGQUIT 4)SIGILL 5)SIGTRAP 6)SIGABRT 7)SIGBUS 8)SIGFPE
?? ?9)SIGKILL 10) SIGUSR1 11)SIGEGV 12)SIGUSR2 13)SIGPIPE 14)SIGALRM 15)SIGTERM 17)SIGCHLD
?? ?18)SIGCONT 19)SIGSTOP ... ...
?? ?見(jiàn)如下示例腳本:
??? /> trap 'rm tmp*;exit 1' 1 2 15????? #該命令表示在收到信號(hào)1、2和15時(shí),該腳本將先執(zhí)行rm tmp*,然后exit 1退出腳本。
??? /> trap 2?? ??? ??? ??? ??? ??? ??? ?????????? #當(dāng)收到信號(hào)2時(shí),將恢復(fù)為以前的動(dòng)作,即退出。
??? /> trap " " 1 2?? ??? ??? ??? ??? ??? ?????? #當(dāng)收到信號(hào)1和2時(shí),將忽略這兩個(gè)信號(hào)。
??? /> trap -?? ??? ??? ??? ??? ??? ??? ?????????? #表示恢復(fù)所有信號(hào)處理的原始值。
??? /> trap 'trap 2' 2?? ??? ??? ??? ??? ??????? #在第一次收到信號(hào)2時(shí),執(zhí)行trap 2,這時(shí)將信號(hào)2的處理恢復(fù)為缺省模式。在收到信號(hào)2時(shí),Shell程序退出。
??? /> cat > test2.sh
?? ?trap 'echo "Control+C will not terminate $0."' 2?? #捕獲信號(hào)2,即在鍵盤(pán)上按CTRL+C。
??? trap 'echo "Control+\ will not terminate $0."' 3?? #捕獲信號(hào)3,即在鍵盤(pán)上按CTRL+\。
??? echo "Enter stop to quit shell."
?? ?while true?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???????????????? #無(wú)限循環(huán)。
?? ?do
??????? echo -n "Go Go...."
??????? read
??????? if [[ $REPLY == [Ss]top ]]?? ??? ??? ??? ? ??? ?????? #直到輸入stop或Stop才退出循環(huán)和腳本。
?????? then
??????????? break
??????? fi
?? ?done
?? ?CTRL+D
?? ?/> . ./test2.sh
?? ?Enter stop to quit shell.
?? ?Go Go....^CControl+C will not terminate -bash.
?? ?^\Control+\ will not terminate -bash.
??? stop

??? 8.? 用getopts處理命令行選項(xiàng):

?? ?這里的getopts命令和C語(yǔ)言中的getopt幾乎是一致的,因?yàn)槟_本的位置參量在有些時(shí)候是失效的,如ls -lrt等。這時(shí)候-ltr都會(huì)被保存在$1中,而我們實(shí)際需要的則是三個(gè)展開(kāi)的選項(xiàng),即-l、-r和-t。見(jiàn)如下帶有g(shù)etopts的示例腳本:
??? /> cat > test3.sh
?? ?#!/bin/sh
?? ?while getopts xy options?????????????????????????? #x和y是合法的選項(xiàng),并且將-x讀入到變量options中,讀入時(shí)會(huì)將x前面的橫線去掉。
??? do
??????? case $options in
??????? x) echo "you entered -x as an option" ;;????? ?
??????? y) echo "you entered -y as an option" ;;
??????? esac
?? ?done
??? /> ./test3.sh -xy
?? ?you entered -x as an option
?? ?you entered -y as an option
??? /> ./test3.sh -x
?? ?you entered -x as an option
??? /> ./test3.sh -b?????????????????????????????????????? #如果輸入非法選項(xiàng),getopts會(huì)把錯(cuò)誤信息輸出到標(biāo)準(zhǔn)錯(cuò)誤。
?? ?./test3.sh: illegal option -- b
??? /> ./test3.sh b??????????????????????????????????????? #該命令不會(huì)有執(zhí)行結(jié)果,因?yàn)閎的前面有沒(méi)橫線,因此是非法選項(xiàng),將會(huì)導(dǎo)致getopts停止處理并退出。

??? /> cat > test4.sh
?? ?#!/bin/sh
?? ?while getopts xy options 2>/dev/null???????? #如果再出現(xiàn)選項(xiàng)錯(cuò)誤的情況,該重定向會(huì)將錯(cuò)誤輸出到/dev/null。
??? do
?? ???? case $options in
?? ???? x) echo "you entered -x as an option" ;;
?? ???? y) echo "you entered -y as an option" ;;
?? ???? \?) echo "Only -x and -y are valid options" 1>&2 # ?表示所有錯(cuò)誤的選項(xiàng),即非-x和-y的選項(xiàng)。
??? esac
?? ?done
?? ?/> . ./test4.sh -g ?? ??? ??? ??? ??? ??? ??? ??? ??? ?#遇到錯(cuò)誤的選項(xiàng)將直接執(zhí)行\(zhòng)?)內(nèi)的代碼。
?? ?Only -x and -y are valid options
??? /> . ./test4.sh -xg
?? ?you entered -x as an option
?? ?Only -x and -y are valid options

??? /> cat > test5.sh
?? ?#!/bin/sh
?? ?while getopts xyz: arguments 2>/dev/null?#z選項(xiàng)后面的冒號(hào)用于提示getopts,z選項(xiàng)后面必須有一個(gè)參數(shù)。
??? do
??????? case $arguments in
??????? x) echo "you entered -x as an option." ;;
??????? y) echo "you entered -y as an option." ;;
??????? z) echo "you entered -z as an option."? #z的后面會(huì)緊跟一個(gè)參數(shù),該參數(shù)保存在內(nèi)置變量OPTARG中。
??????????? echo "\$OPTARG is $OPTARG.";
?????????? ;;
??????? \?) echo "Usage opts4 [-xy] [-z argument]"
??????????? exit 1 ;;
??????? esac
?? ?done
?? ?echo "The number of arguments passed was $(( $OPTIND - 1 ))" #OPTIND保存一下將被處理的選項(xiàng)的位置,他是永遠(yuǎn)比實(shí)際命令行參數(shù)多1的數(shù)。
??? /> ./test5.sh -xyz foo
?? ?you entered -x as an option.
?? ?you entered -y as an option.
?? ?you entered -z as an option.
?? ?$OPTARG is foo.
?? ?The number of arguments passed was 2
??? /> ./test5.sh -x -y -z boo
?? ?you entered -x as an option.
?? ?you entered -y as an option.
?? ?you entered -z as an option.
?? ?$OPTARG is boo.
?? ?The number of arguments passed was 4

??? 9.? eval命令與命令行解析:
?? ?eval命令可以對(duì)命令行求值,做Shell替換,并執(zhí)行命令行,通常在普通命令行解析不能滿足要求時(shí)使用。
??? /> set a b c d
?? ?/> echo The last argument is \$$#
?? ?The last argument is $4
??? /> eval echo The last argument is \$$#??? #eval命令先進(jìn)行了變量替換,之后再執(zhí)行echo命令。
?? ?The last argument is d


總結(jié)

以上是生活随笔為你收集整理的Linux Shell常用技巧(十二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。