編寫shell腳本--自頂向下設計

一、shell函數

我們的報告當前執行如下步驟,即可生成HTML文檔。

  1. 打開頁面
  2. 打開頁面標題
  3. 設置頁面標題
  4. 關閉頁面標題
  5. 打開頁面主體
  6. 輸出頁面主體
  7. 輸出時間戳
  8. 關閉頁面主體
  9. 關閉頁面

爲了下一階段的開發,我們將在步驟7和步驟8之間額外添加一些任務,如下所示。

  • 系統正常運行時間和負載。這是自上次關機或重啓之後系統的運行時間,在幾個時間間隔內,當前運行在處理器上的平均任務量。
  • 磁盤空間。系統存儲空間的使用情況。
  • 用戶空間。每個用戶所使用的存儲空間。

在這些任務中,如果每個任務都有一條對應的命令,我們可以直接通過命令替換的方式,將它們添加到腳本中。

#!/bin/bash

#Program to output a system information page

TITLE="System Information Report For $HOSTNAME"

CURRENT_TIME=$(date +"%x %r %Z")
TIME_STAMP="Generated $CURRENT_TIME,by #USER"

cat  << _EOF_
 <HTML>
					<HEAD>
							<TITLE>$TITLE</TITLE>
					</HEAD>
					<BODY>
							<H1>$TITLE</H1>
							<P>$TIME_STAMP</P>
							$(report_uptime)
							$(report_disk_space)
							$(report_home_space)
					</BODY>
</HTML>
_EOF_

我們可以通過兩種方式創建這些額外的命令。我們可以編寫3個獨立的腳本,並把它們放置到環境變量PATH所列出的目錄中,或者是我們可以將腳本作爲shell函數嵌入到程序i中。shell函數是位於其他腳本中的迷你腳本,可以用作自主程序(autonomous program)。shell函數由兩種語法形式。第一種如下所示:

function name {
		commands
		return
}

其中name是指示這個函數的名稱,commands是這個函數中的一系列命令。第二種看起來如下所示:

name() {
		commands
		return
}

這兩種格式等價,並且可以交替使用。來看下面這個腳本,它演示了shell函數的使用。

#!/bin/bash

#shell function demo

function funct {
		echo "Step 2"
		return
}

#Main program starts here

echo  "Step 1"
funct
echo  "Step 3"

當shell讀取腳本的時候,它會跳過1~11行,這些行包含的是註釋和函數的定義。執行從帶有echo命令的第12行開始。第13行調用了shell函數funct,shell會執行這個函數,而且其執行方式與執行其他命令時相同。程序控制權然後移動到第6行,執行第二個echo命令,隨後再執行第7行。這個return命令終止函數的執行,然後將控制權漢給函數調用後面的代碼(第14行),然後執行最後一個echo命令。

注意:爲了讓函數調用被識別爲shell函數,而不是被解釋爲外部程序的名字,shell函數的定義在腳本中的位置必須在它被調用的前面。

我們在腳本中添加上最小的shell函數定義:

#!/bin/bash

#Program to output a system information page

TITLE="System Information Report For $HOSTNAME"
CURRENT_TIME=$(date +"%x %r %Z")
TIME_STAMP="Generated $CURRENT_TIME,by #USER"

report_uptime () {
	return
}
report_disk_space () {
	return
}
report_home_space () {
	return
}
cat  << _EOF_
 <HTML>
					<HEAD>
							<TITLE>$TITLE</TITLE>
					</HEAD>
					<BODY>
							<H1>$TITLE</H1>
							<P>$TIME_STAMP</P>
							$(report_uptime)
							$(report_disk_space)
							$(report_home_space)
					</BODY>
</HTML>
_EOF_

shell函數的命令規則和變量相同。一個函數必須至少包含一條命令。return命令(可選的)可以滿足該要求。

二、局部變量

在目前我們所編寫的腳本中,所有的變量(包括常量)都是全局變量。全局變量在整個程序期間會一直存在。在很多情況下,這很不錯。但是有時候,它會讓shell函數的使用變得複雜。在shell函數中,經常需要的是局部變量。局部變量僅僅在定義他們的shell函數中有效,一旦shell函數終止,它們就不再存在。
局部變量可以讓程序員使用已經存在的變量名稱,無論是腳本中的全局變量,還是其他shell函數中的變量,而不用考慮潛在的命名衝突。
下面是一個顯示如何定義和使用局部變量的腳本示例。

#!/bin/bash

#local-vars: script to demonstrate local variables

foo=0  #global variable foo

funct_1 () {
	local foo # variable foo local to funct_1
	foo=1
	echo "funct_1:  foo=$foo"
}
funct_2 () {
	local foo # variable foo local to funct_2
	foo=2
	echo "funct_2: foo=$foo"
}

echo "global: foo = $foo"
funct_1
echo "global: foo = $foo"
funct_2
echo "global: foo = $foo"

可以看到,局部變量是通過在變量名前面添加單詞local來定義的。這樣,就創建並同時定義了一個shell函數中的局部變量。一旦出了這個shell函數,這個局部變量將不再存在。當運行腳步時,結果如下所示:

[wangjichuan@Jarvis ~]$ local-vars
global: foo = 0
funct_1: foo=1
global: foo = 0
funct_2: foo=2
global: foo = 0

可以看到,在兩個shell函數中對局部變量foo的賦值,不影響shell函數以外定義的變量foo的值。
這個特性可以讓我們編寫的shell函數相互獨立,而且也獨立於它們所在的腳本。這非常有用,因爲它有助於阻止程序中各個部分的相互干擾。該特性也可以讓我們編寫出可移植的shell函數。也就是說,我們可以根據需要將某一腳本中的shell函數剪切下來,然後粘貼到另外一個腳本中。

三、保持腳本的運行

在開發程序時,讓程序保持可運行的狀態會非常有用。通過這種方式,並經常測試,就可以在開發過程的早期檢測到錯誤。這也會讓問題的調試變得容易。例如,如果我們運行某個程序,並對它做了細微的改動,然後再次運行該程序,此時發現了問題。這可能時最近的改動導致的。通過添加空函數(程序員將其成爲stub),我們可以在早期驗證程序的邏輯流程。當構建一個stub時,最好時包含一些能夠爲程序員提供反饋信息的東西,這些反饋信息可以顯示正在執行的邏輯流程。

report_uptime () {
	cat <<- _EOF_
					<H2>System Uptime</H2>
					<PRE>$(UPTIME)</PRE>
					_EOF_
	return
}

該函數的代碼直接了當。我們使用了一個here文檔來輸出一個標題,並輸出uptime命令的結果。命令結果使用

標籤圍起來,其目的是保留命令的格式。report_disk_space函數也類似。

report_disk_space () {
	cat <<- _EOF_
					<H2>Disk Space Utilization</H2>
					<PRE>$(df -h)</PRE>
					_EOF_
	return
}

這個函數使用了df -h這個命令來檢查磁盤的空間。隨後,我們來構建report_home_space函數。

report_home_space () {
	cat <<- _EOF_
					<H2>Home Space Utilization</H2>
					<PRE>$(du -sh /home/*)</PRE>
					_EOF_
	return
}

我們使用帶-sh選項的du命令來執行這個任務。這個並不是問題的完整解決方案。雖然可以在某些操作系統中(例如Ubuntu)運行,但是在其他系統中則無效。這是因爲很多系統設置了主目錄的權限,以防止被其他用戶讀取,這種安全措施也很合理。在這些操作系統中,只有在超級用戶運行我們的腳本時,我們編寫的這個report_home_space函數纔會執行。一個更好的解決方案是讓腳本根據用戶的權限調整自己的行爲。
在這裏插入圖片描述

你的.bashrc文件中的shell函數

shell函數可以很好的取代別名,並且實際上也是創建個人使用的小命令的首選方法。別名非常侷限於命令的種類和它們所支持的shell特性,而shell特性則允許任何可以編寫爲腳本的東西。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章