跳轉至內容

Ict-創新/LPI/105.2

來自華夏公益教科書,開放的書籍,為開放的世界

105.2 自定義或編寫簡單的指令碼

[編輯 | 編輯原始碼]

考生應該能夠自定義現有指令碼,或編寫簡單的新的 BASH 指令碼。


關鍵知識領域

  • 使用標準 sh 語法(迴圈、測試)。
  • 使用命令替換。
  • 測試返回值以判斷命令成功或失敗或其他資訊。
  • 執行有條件的郵件傳送給超級使用者。
  • 透過 shebang(#!)行正確選擇指令碼直譯器。
  • 管理指令碼的位置、所有權、執行和 suid 許可權。

什麼是 shell 指令碼?

[編輯 | 編輯原始碼]

shell 指令碼是一個文字檔案,它告訴 shell 該做什麼。

它包含用作指令碼其餘內容直譯器的程式的名稱。以 #!ProgramPath+Name 開頭的行(通常是第一行)指定要使用的直譯器

#!/bin/bash 或 #!/bin/sh 或 #!/usr/bin/perl -w

實際上,當系統被要求啟動一個指令碼時,它會讀取以 #! 開頭的行,啟動相應的指令碼直譯器,該直譯器依次讀取指令碼並執行其中包含的命令。

執行指令碼的條件

指令碼檔案必須可由執行它的使用者執行(chmod ....)。直譯器必須位於指令碼指定的位置:預設情況下會呼叫 bash。

shell 指令碼中使用的語言

指令碼語言取決於使用的指令碼直譯器。bash 有自己的語法,可以在互動模式或指令碼中使用。

向指令碼傳遞引數

指令碼可以被賦予最多 9 個位置引數(適用於所有直譯器)或最多 99 個引數(適用於 bash)。

在指令碼內部,每個引數將被標識為 $1 到 $9 或 ${10} 到 ${99}

scriptname param1 param2 param3 param4..... param47.....$0 $1 $2 $3 $4 ${47} .....

一些特殊引數由 Bourne shell 自動設定,通常不能直接設定或修改。

引數 $n 可以透過指令碼內部的 set 命令修改。(其中 n 是 1-99 適用於 bash)

set aaa bbb ccc ... $1 $2 $3

特殊引數

[編輯 | 編輯原始碼]

$n - 位置引數 n,最大 n=9($0 是 shell 指令碼的名稱)

${nn} - 位置引數 nn(對於 nn>9)

$# - 位置引數的數量(不包括指令碼程式)

$@, $* - 所有位置引數

"$@" - 與 "$1" "$2" . . . "$n" 相同

"$*" - 與 "$1c$2c . . . $n" 相同,c = $IFS 的內容(預設是空格)

$? - 上一個命令的退出狀態

$$ - 當前 shell 的程序 ID

$- - 當前生效的選項

$! - 上一個後臺命令的程序 ID

$- 當前 shell 的名稱(在本例中為 'bash')

shift 命令

shift 命令將位置引數的賦值向左移動。如果一個

指令碼被這樣呼叫

script1 aaa bbb ccc ddd

並且以下命令在指令碼內部執行

# echo $1 $2 $3

# shift

# echo $1 $2 $3

第一個 echo 命令的結果是

aaa bbb ccc

第二個 echo 命令的結果是

bbb ccc


set 和 unset 命令

unset 命令通常用於取消設定變數的值,set 命令用於從指令碼內部為位置引數賦值。如果一個指令碼在沒有位置引數的情況下啟動,並且在驗證這一點後,指令碼為它們分配預設值,則非常有用。

set aa bb cc dd $1 $2 $3 $4 - 將 aa 賦值給 $1,bb 賦值給 $2,cc 賦值給 $3,dd 賦值給 $4

set 命令也用於改變 bash 行為的屬性。

set 的一個重要選項是

# set -o noclobber

該命令會導致重定向符號 (>) 無法覆蓋現有檔案的內容。

條件語句

[編輯 | 編輯原始碼]

以下列出了最常用的條件指令

if 條件分支指令

if - 允許只有在滿足特定條件時才執行某些命令。

語法:(另請參閱本主題後面的“條件表示式”部分)

if <condition_is_true> ; then

run_these_commands

.................

elseif <condition_is_true> ; then

如果第一個條件不滿足而此條件滿足,則

run_these_commands

.................

else

如果以上所有條件都不滿足,則

run_these_commands_instead

.................

fi

if 指令塊的結束

<condition_is_true> 可以是以下型別

(1) 測試檔案或目錄的狀態。

if test -e /etc/fstab ; then

if [ -e /etc/fstab ] ; then

(2) 命令或指令碼退出程式碼。

if (ifconfig | grep 'ppp0') ; then

(3) 變數的內容與某個值相對應

if $1 ; then - 如果 $1 包含值,則為真

if [ "$net" = "eth0" ] ; then - 測試字串

if test ["$#" -eq 5 ] ; then

(整數測試)


case 條件分支指令

case 通常用於根據

變數的內容,有條件地分支到多個選項之一。

語法

case <Variable> in

<choice1>)

要執行的命令

;;

choice2)

要執行的命令

;;

choice3)

要執行的命令

;;

*)

如果以上所有條件都不滿足,則要執行的命令。

;;

case


case 指令塊的結束

指令碼中的迴圈

在需要多次執行一系列命令時使用。

while 條件迴圈指令

while 指令只要其條件(在 while 語句中定義)滿足,就會一直迴圈並執行其塊中的命令。

語法:

while <condition_is_true> ; do

run_these_commands

done

while 指令塊的結束


注意:while 通常用於詢問使用者輸入某種鍵盤輸入,如果響應不合適,則會重複請求,直到輸入正確的資訊。然後退出 while 迴圈,程式繼續執行。

until 條件迴圈指令

until 迴圈的工作方式與 while 迴圈完全相同,只是邏輯相反。

迴圈一直持續到條件滿足。

語法:

until <condition_is_true> ; do

run_these_commands

done

until 指令塊的結束

for 迴圈指令

for 指令允許在一系列命令中執行的次數與給定列表中的專案數量相同。每次迴圈執行時,特定變數的內容都會變成給定列表中當前專案的 value。

語法:

for variable in list ; do

run_these_commands

done

for 指令塊的結束

variable = 將內容變成給定列表中每次迴圈的當前專案的變數名。列表也可以是一個包含專案列表的變數。

for item in ~/file1 ~/file2 ~/file3 ; do

echo "------------ Content of $item -----------"

cat $item >> ~/allfiles

done

Shell 函式

[編輯 | 編輯原始碼]

Shell 函式是一系列儲存在某個地方的命令,可以在指令碼中的多個位置使用。可以透過位置引數向函式傳遞引數。

位置引數($1、$2、$3 ...)將成為函式的區域性變數。它們使用與指令碼相同的語法,但第一個($0)保持全域性變數。

變數 FUNCNAME 用於與 $0 相似,用於相同的目的。

像 $#、$*、$@ 這樣的特殊變數在函式中也是區域性的。

所有其他變數對於指令碼來說是全域性的,並且可以被函式修改。

命令 return x(x=返回值)可以用作函式退出命令,並用於分配函式返回值。

語法:

FunctionName () {

command ;

command ;

}

function FunctionName () {

command ;

command ;

}

(有關 Shell 函式的更多詳細資訊,請參見上一節“自定義和使用 Shell 環境”中的函式。)

退出程式碼和變數 $?

所有程式(包括指令碼)在程序結束時都會返回一個退出程式碼。退出程式碼有助於確定程式或指令碼的成功或失敗。可以透過特殊變數 $? 讀取此退出程式碼,並用於在呼叫指令碼中做出進一步的決策。

通常,“0”的退出程式碼表示成功,任何其他程式碼(1-255)表示某種失敗。它也常被稱為錯誤程式碼。

&& 和 || 條件分支

退出程式碼可用於根據其成功或失敗執行另一個命令(僅一個)。雙安培符號“&&”用於指定在退出程式碼成功(0)時執行的命令。雙管道“||”用於指定在退出程式碼不成功(1-255)時執行的命令。

示例

# ifconfig ppp0 && echo "pppd running" || echo "pppd not running"

如果命令 ifconfig ppp0 成功,則將執行命令 echo "pppd running"(&&),否則將執行命令 echo "pppd not running"。

從指令碼向 root 傳送郵件

有時,向 root 或其他使用者傳送郵件,以宣佈自動指令碼執行中的某些異常或成功是很有用的。通常使用的程式是“mail”。有關它使用的所有選項,請參閱 man mail。

語法1:

# mail -s "subject" destination_mail_address "message.."

語法2:

# program | mail -s "subject" destination_mail_address

語法3:

# mail -s "subject" destination_mail_address <

message body.......

EOM

示例:

# df | mail -s "HD Space on $(date)" root

將命令 df 的結果傳送到本地 root 使用者。

Bash 指令碼的位置和安全性

管理指令碼通常儲存在 PATH 中,該路徑是 /usr/local/bin 或 /root/bin。正常的訪問許可權為 755(rwx r-x r-x) 或為了透過防止除 root 之外的任何其他使用者執行它來獲得更多保護:700(rwx --- ---)。

雖然 SUID 對指令碼沒有任何影響,但非常舊版本的 Linux 可能會受到 SUID 設定的影響。

條件表示式

[edit | edit source]

test 和 [...] 命令用於使用檔案屬性、字串和整數評估條件表示式。基本格式為:test expression 或 [ expression ],其中 expression 是您正在評估的條件。在左括號之後和右括號之前必須有空格。空格還必須分隔表示式引數和運算子。如果表示式計算結果為真,則返回零退出狀態,否則表示式計算結果為假並返回非零退出狀態。

測試檔案運算子

-a <file> 如果檔案存在,則為真。

-b <file> 如果檔案存在且是塊特殊檔案,則為真。

-c <file> 如果檔案存在且是字元特殊檔案,則為真。

-d <file> 如果檔案存在且是目錄,則為真。

-e <file> 如果檔案存在,則為真。

-f <file> 如果檔案存在且是普通檔案,則為真。

-g <file> 如果檔案存在且設定了組 ID,則為真。

-h <file> 如果檔案存在且是符號連結,則為真。

-k <file> 如果檔案存在且其“粘性”位已設定,則為真。

-p <file> 如果檔案存在且是命名管道 (FIFO),則為真。

-r <file> 如果檔案存在且可讀,則為真。

-s <file> 如果檔案存在且大小大於零,則為真。

-t <fd> 如果檔案描述符 fd 已開啟並引用終端,則為真。

-u <file>如果檔案存在且其 SUID 位已設定,則為真。

-w <file>如果檔案存在且可寫,則為真。

-x <file> 如果檔案存在且可執行,則為真。

-O <file> 如果檔案存在且由有效 UID 擁有,則為真。

-G <file> 如果檔案存在且由有效 GID 擁有,則為真。

-L <file> 如果檔案存在且是符號連結,則為真。

-S <file> 如果檔案存在且是套接字,則為真。

-N <file> 如果檔案存在且自上次讀取後已修改,則為真。

file1 -nt file2 如果 file1 比 file2 更新(根據修改日期),或者 file1 存在而 file2 不存在,則為真。

file1 -ot file2 如果 file1 比 file2 舊,或者 file2 存在而 file1 不存在,則為真。

file1 -ef file2 如果 file1 和 file2 引用同一個裝置和 inode 號,則為真。


測試字串運算子

-n string 如果字串的長度不為零,則為真

-z string 如果字串的長度為零,則為真

string 如果字串未設定為 null,則為真

string1 = string2 如果 string1 等於 string2,則為真

string1 = string2 如果 string1 等於 string2,則為真

string1 != string2 如果 string1 不等於 string2,則為真

string1 < string2 如果 string1 在當前語言環境中按字典順序排在 string2 之前,則為真。

string1 > string2 如果 string1 在當前語言環境中按字典順序排在 string2 之後,則為真。

string = pattern 如果字串與模式匹配,則為真

string != pattern 如果字串與模式不匹配,則為真


測試整數運算子

exp1 -eq exp2 如果 exp1 等於 exp2,則為真,例如 [ "$#" -eq 4 ]

exp1 -ne exp2 如果 exp1 不等於 exp2,則為真,例如 test "$#" -ne 3

exp1 -le exp2 如果 exp1 小於或等於 exp2,則為真

exp1 -lt exp2 如果 exp1 小於 exp2,則為真

exp1 -ge exp2 如果 exp1 大於或等於 exp2,則為真

exp1 -gt exp2 如果 exp1 大於 exp2,則為真


其他測試運算子

! exp 如果給定表示式為假,則為真,例如 [ ! -r /etc/motd ]

exp1 -a exp2 如果 exp1 和 exp2 都計算結果為真,則為真(見下面的示例)

exp1 -o exp2如果 exp1 或 exp2 至少有一個計算結果為真,則為真

\( exp \) 如果 exp 為真,則為真;用於對錶達式進行分組

\ 用於轉義括號。在此字元前後使用空格

[ "$A" = "$B" -a \( "$C" = "$D" -a "$E" = "$F" \) ]



以下是使用過的檔案、術語和實用程式的部分列表。* 用於

  • while
  • test
  • if
  • read
  • seq


上一章 | 下一章

華夏公益教科書