接詳細介紹Linux shell腳本基礎學習(一)我們來看一下shell中Here documents和函數的使用。
6. Here documents
HERE Document是bash里面定義塊變量的途徑之一
定義的形式為:
命令<<HERE
...
...
...
HERE
它的作用即可以用來定義一段變量,會把命令和HERE之間的內容利用轉向輸入的方式交給該命令去處理。其中HERE相當於標記,可以是任何的字符串。注意后一個HERE的最后不要有空格,否則會報錯。
使用HERE Document用在變量設定:
[aa@aa shell]$ wow='Wow,great!' [aa@aa shell]$ m1=$(cat <<Here > Line 1 is good. > They are jack,marry and john. > $wow > Here > ) [aa@aa shell]$ echo $m1 Line 1 is good. They are jack,marry and john. Wow,great!
注意這里HERE還有一個特殊的用法 :
就是在HERE前面加上-或者給HERE加上' ',加上-表明下述文字段所有TAB鍵將全部忽略,加上' '表明以下凡是變量定義用到了' ',將會使變量呈現所見即所得的形式,也即關閉變量替換;如果加上的是" "雙引號,則會進行變量替換。
[aa@aa shell]$ wow='Wow,great!' [aa@aa shell]$ m1=$(cat <<'Here' > Line 1 is good. > They are jack,marry and john. > $wow > Here > ) [aa@aa shell]$ echo $m1 Line 1 is good. They are jack,marry and john. $wow
注意:這里的$wow被原樣輸出了。至於加上-的效果這里不細說,大家可自行測試。
它也可以用來定義一段注釋 ,利用HERE Document做多行批注,方法是:
:<<HERE
這是第一行批注
這是第二行批注
這是第三行批注
其它行,類推
HERE
:代表什么都不做
原本bash只支持單行批注(用#表示),現就可用於多行注釋了,此處不細說。
當要將幾行文字傳遞給一個命令時,here documents是一種不錯的方法。對每個腳本寫一段幫助性的文字是很有用的,此時如果我們四有那個 here documents就不必用echo函數一行行輸出。 一個 "Here document" 以 << 開頭,后面接上一個字符串,這個字符串還必須出現在here document的末尾。
下面我們來看一個例子,在該例子中,我們對多個文件進行重命名,並且使用here documents打印幫助:
1 #!/bin/sh 2 # we have less than 3 arguments. Print the help text: 3 if [ $# -lt 3 ] ; then 4 cat <<help 5 -- renames a number of files using sed regular expressions 6 USAGE: $0 'regexp' 'replacement' files... 7 EXAMPLE: rename all *.HTM files in *.html: 8 $0 'HTM$' 'html' *.HTM 9 help 10 exit 0 11 fi 12 13 OLD="$1" 14 NEW="$2" 15 # The shift command removes one argument from the list of 16 # command line arguments. 17 shift 18 shift 19 # $* contains now all the files: 20 for file in $*; do 21 if [ -f "$file" ] ; then 22 newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"` 23 if [ -f "$newfile" ]; then 24 echo "ERROR: $newfile exists already" 25 else 26 echo "renaming $file to $newfile ..." 27 mv "$file" "$newfile" 28 fi 29 fi 30 done
執行腳本:
[aa@aa shell]$ ll 總用量 4 -rw-rw-r--. 1 yongli yongli 0 2月 17 14:06 a.html -rw-rw-r--. 1 yongli yongli 0 2月 17 14:06 b.html -rw-rw-r--. 1 yongli yongli 0 2月 17 14:06 c.html -rwxrwxr-x. 1 yongli yongli 681 2月 17 14:21 here_doc.sh
[aa@aa shell]$ /data/shell/here_doc.sh -- renames a number of files using sed regular expressions USAGE: /data/shell/here_doc.sh 'regexp' 'replacement' files... EXAMPLE: rename all *.HTM files in *.html: /data/shell/here_doc.sh 'HTM$' 'html' *.HTM
[aa@aa shell]$ /data/shell/here_doc.sh 'htm$' 'html' *.htm renaming a.htm to a.html ... renaming b.htm to b.html ... renaming c.htm to c.html ...
下面讓我們詳細說明下。
第一個if表達式判斷輸入命令行參數是否小於3個 (特殊變量$#表示包含參數的個數) 。如果輸入參數小於3個,則將幫助文字傳遞給cat命令,然后由cat命令將其打印在屏幕上。打印幫助文字后程序退出($0: 表示當前腳本的名稱)。
如果輸入參數等於或大於3個,我們 就將第一個參數賦值給變量OLD,第二個參數賦值給變量NEW。
下一步,我們使用shift命令將第一個和第二個參數從參數列表中刪除,這樣原來的第三個參數就成為參數列表$*的第一個參數。
然后我們開始循環,命令行參數列表被一個接一個地被賦值給變量$file。
接着我們判斷該文件是否存在,如果存在則通過sed命令搜索和替換來產生新的文件名。然后將反短斜線內命令結果賦值給newfile。這樣我們就達到了我們的目的:得到了舊文件名和新文件名。然后使用mv命令進行重命名。
這里再看一個實例,利用HERE Document,打包C(或其它程序語言)的原始碼。這是Cracker散布安全漏洞程序,最喜歡的方法。
#!/bin/bash # Filename:create_prg.sh echo "creating hello.c..." echo cat <<'EOF' > hello.c #include <stdio.h> int main() { printf("Hello world!\n"); return 0; } EOF echo "compiling hello.c..." #compile hello.c,create the excutable file gcc -o hello hello.c #if compile successfully,then excute it if [ $? -eq 0 ];then echo "excute hello..." chmod u+x hello ./hello else echo 'Compile Error:hello.c' fi
7.函數
函數是一串命令的集合,函數可以把大的命令集合分解成若干較小的任務。編程人員可以基於函數進一步的構造更復雜的Shell 程序,而不需要重復編寫相同的代碼。
基本形式:
function_name()
{
command1
command2
…
commandN
}
對函數結構進行解釋:
其中標題:函數名,函數體:函數內的命令集合,在編寫腳本時要注意標題名應該唯一,如果不唯一,腳本執行時會產生錯誤。
在函數名前可以加上關鍵字function,但加上和省略關鍵字function對腳本的最終執行不產生任何影響。
函數體中的命令集合必須含有至少一條命令,即函數不允許空命令,這一點和C語言不同。
函數之間可通過參數、函數返回值交互,函數在腳本中出現的次序可以是任意的,但是必須按照腳本中的調用次序執行這些函數。
向函數傳遞參數
在bash Shell編程中,向函數傳遞的參數仍然是以位置參數的方式來傳遞的,而不能傳遞數組等其它形式變量,這與C語言或Java語言中的函數傳遞是不同的。
function1.sh
#!/bin/bash half() { let "n = $1" let "n = n/2" echo "In function half() n is $n" } if [ -z $1 ];then echo 'Please input number m.' echo "Uage:$0 number" echo "Example:$0 2" exit 0 fi let "m = $1" echo "Before the function half() is called, m is $m" half $m echo "After the function half() is called, m is $m"
在Linux Shell編程中,函數還可傳遞間接參數,但該方式傳遞方式遠遠沒有C語言和Java語言靈活,而只能使用間接變量引用來傳遞參數,這種方式是一種笨拙的間接參數傳遞方式。
function2.sh
#!/bin/bash ind_func() { echo " $1" } if [ -z $1 ];then echo 'Please input arguments.' echo "Uage:$0 args" echo "Example:$0 a" exit 0 fi parameter=ind_arg ind_arg=Hello ind_func "$parameter" ind_func "${!parameter}" echo "***********************" ind_arg=World ind_func "$parameter" ind_func "${!parameter}"
函數返回值
有時需要腳本執行完成后返回特定的值來完成腳本的后繼操作,這些特定的值就是函數返回值。在Linux Shell編程中,函數通過return返回其退出狀態,0表示無錯誤,1表示有錯誤。在腳本中可以有選擇的使用return語句,因為函數在執行完最后一條語句后將執行調用該函數的地方執行后繼操作。
function3.sh
#!/bin/bash show_week() { echo -n "What you input is: " echo "$1" case $1 in 0) echo "Today is Sunday. " return 0;; 1) echo "Today is Monday. " return 0;; 2) echo "Today is Tuesday. " return 0;; 3) echo "Today is Wednesday. " return 0;; 4) echo "Today is Thursday. " return 0;; 5) echo "Today is Friday. " return 0;; 6) echo "Today is Saturday. " return 0;; *) return 1;; esac } if show_week "$1" then echo "What you input is right! " else echo "What you input is wrong! " fi exit 0
腳本放置多個函數
可以在腳本中放置多個函數,腳本執行時按照調用函數的順序執行這些函數.
function4.sh
#!/bin/bash show_week() { for day in Monday Tuesday Wednesday Thursday Friday Saturday Sunday do echo -n "$day " done echo "" } show_number() { for(( integer = 1; integer <= 7; integer++ )) do echo -n "$integer " done echo "" } show_square() { i=0 until [[ "$i" -gt 7 ]] do let "square=i*i" echo "$i * $i = $square" let "i++" done } show_week show_number show_square
函數相互調用
在Linux Shell編程中,函數之間可以相互調用,調用時會停止當前運行的函數轉去運行被調用的函數,直到調用的函數運行完,再返回當前函數繼續運行。
一個函數調用多個函數
在Linux Shell編程中允許一個函數調用多個函數,在該函數調用其他函數時同樣需要按照調用的順序來執行調用的函數。
局部變量和全局變量
在Linux Shell編程中,可以通過local關鍵字在Shell函數中聲明局部變量,局部變量將局限在函數范圍內。此外,函數也可調用函數外的全局變量,如果一個局部變量和一個全局變量名字相同,則在函數中局部變量將會覆蓋掉全局變量.
函數遞歸
Linux Shell中可以遞歸調用函數,即函數可以直接或間接調用其自身。在遞歸調用中,主調函數又是被調函數。執行遞歸函數將反復調用其自身,每調用一次就進入新的一層。
function5.sh
#!/bin/bash #遞歸調用函數 foo() { read y foo $y echo "$y" } #調用函數 foo exit 0
使用局部變量進行遞歸一般是針對數值運行來使用的。階乘運算是一個使用局部變量的遞歸調用過程,實現了n! 的運算,其可以通過下面的公式表示:
n!=1 (n=0)
n!=n*(n-1)! (n>=1)
按照該公式可實現對階乘的運算,由於該階乘運算中存在終止條件“0!=1”,所以可以使用函數遞歸來實現該運算。
function6.sh
#!/bin/bash #$1的階乘 fact () { local num=$1 if [ "$num" -eq 0 ] then factorial=1 else let "decnum=num-1" fact $decnum let "factorial=$num * $?" fi return $factorial } if [ -z $1 ];then echo 'Please input an intger number argument.' echo "Uage:[$0 args]" echo "Example:[$0 5]" exit 0 fi fact $1 echo "Factorial of $1 is $?" exit 0
ok.到這里先暫告一段落,其他的后續寫出。