本文的主要內容:1、編寫Shell腳本的一般步驟
2、在Shell腳本中輸出文本 3、Shell腳本中的變量
4、Shell腳本中的函數 5、流程控制:if 分支結構
6、Shell中讀取鍵盤輸入一、編寫Shell 腳本
一般步驟:1.編寫一個腳本 2.使腳本文件可執行 3.把腳本放置到 shell 能夠找到的地方例如:
1.編寫hello_world腳本
#!/bin/bash # This is our first script. echo 'Hello World!'2.賦予可執行權限
chmod 700 hello_world3.執行腳本
./hello_world4.若想讓系統中的每個用戶都可以使用, 那麼可將腳本放到 /usr/local/bin,系統管理員使用的腳本經常放到 /usr/local/sbin 目錄下。
二、Shell中輸出文本使用echo方式
例如:
echo "a string"使用"here document"方式(可以隨意的嵌入引號)
格式如下:
command << token
text
token
這裡的 command 是一個可以接受標准輸入的命令名,token 是一個用來指示嵌入文本結束的字符串
把操作符"<<"改為 "<<-",shell 會忽略開頭的 tab 字符,可使用縮進提高可讀性
例如:
cat << _EOF_ a string _EOF_或
cat <<- _EOF_ a string _EOF_例子:使用 一個 here document 將一系列的命令傳遞到 ftp 程序中以從一個遠端 FTP 服務器中得到一個文件
#!/bin/bash # Script to retrieve a file via FTP FTP_SERVER=*** FTP_PATH=*** REMOTE_FILE=*** ftp -n << _EOF_ open $FTP_SERVER user anonymous me@linuxbox cd $FTP_PATH hash get $REMOTE_FILE bye _EOF_ ls -l $REMOTE_FILE三、Shell腳本中的變量
創建變量或給變量賦值variable=value(注:等號左右不能有空格)
可以在同一行中對多個變量賦值a=5 b="a string"
使用變量$variable 或 ${variable}
例如
b="a string"
c="a string and $b"
mv $filename ${filename}1四、Shell中的函數函數語法形式(其中name為函數名,commands為一系列包含在函數中的命令,函數中須至少包含一條命令,return為可選)
function name {
commands
return
}
或
name () {
commands
return
}
*例如
#!/bin/bash
function_1 () {
echo "Function_1 executed."
return
}
cat << _EOF_
$(function_1)
_EOF_局部變量*例如
funct_1 () {
local foo #funct_1中的局部變量
foo=1
echo "funct_1: foo = $foo"
}五、流程控制:if 分支結構if 語句語法如下if commands; then
commands
[elif commands; then
commands...]
[else
commands]
fi
*例如:
x=5
if [ $x = 5 ]; then
echo "x equals 5."
else
echo "x does not equal 5."
fi退出狀態當命令執行完畢後會給系統發送一個值,叫做退出狀態。Shell 提供了一個參數$?可用來檢查退出狀態
例如:(狀態0為命令執行成功)
$ ls -d /usr/bin
/usr/bin
$ echo $?
0
測試*經常與 if 一塊使用的命令是 test。test 命令執行各種各樣的檢查與比較,它有兩種等價模式:
test expression
或
[ expression ]
*其中expression 為一個表達式,其執行結果是 true 或者是 false。當表達式為真時,這個 test 命令返回一個0退出狀態,當表達式為假時,test 命令退出狀態為1
測試表達式*文件表達式
file1 -ef file2:file1 和 file2 擁有相同的索引號(通過硬鏈接兩個文件名指向相同的文件)
file1 -nt file2:file1新於 file2
file1 -ot file2:file1早於 file2
-b file:file 存在並且是一個塊(設備)文件
-c file:file 存在並且是一個字符(設備)文件
-d file:file 存在並且是一個目錄
-e file:file 存在
-f file:file 存在並且是一個普通文件
-g file:file 存在並且設置了組 ID
-G file:file 存在並且由有效組 ID 擁有
-k file:file 存在並且設置了它的“sticky bit”
-L file:file 存在並且是一個符號鏈接
-O file:file 存在並且由有效用戶 ID 擁有
-p file:file 存在並且是一個命名管道
-r file:file 存在並且可讀(有效用戶有可讀權限)
-s file:file 存在且其長度大於零
-S file:file 存在且是一個網絡 socket
-t fd:fd 是一個定向到終端/從終端定向的文件描述符 。 這可以被用來決定是否重定向了標准輸入/輸出錯誤
-u file:file 存在並且設置了 setuid 位
-w file:file 存在並且可寫(有效用戶擁有可寫權限)
-x file:file 存在並且可執行(有效用戶有執行/搜索權限)
*文件表達式例子(其中在表達式中參數$FILE兩邊的引號並不是必需的,但這可防范空參數)
test_file () {
# test-file: Evaluate the status of a file
FILE=~/.bashrc
if [ -e "$FILE" ]; then
if [ -f "$FILE" ]; then
echo "$FILE is a regular file."
fi
if [ -d "$FILE" ]; then
echo "$FILE is a directory."
fi
if [ -r "$FILE" ]; then
echo "$FILE is readable."
fi
if [ -w "$FILE" ]; then
echo "$FILE is writable."
fi
if [ -x "$FILE" ]; then
echo "$FILE is executable/searchable."
fi
else
echo "$FILE does not exist"
return 1
fi
}*字符串表達式string:string 不為 null
-n string:字符串 string 的長度大於零
-z string:字符串 string 的長度為零
string1 = string2或string1 == string2:string1 和 string2 相同. 單或雙等號都可以,不過雙等號更受歡迎
string1 != string2:string1 和 string2 不相同
string1 > string2:sting1 排列在 string2 之後
string1 < string2:string1 排列在 string2 之前
注:> 和 <表達式操作符必須用引號引起來或者是用反斜槓轉義,否則會被 shell 解釋為重定向操作符,造成潛在地破壞結果
*字符串表達式例子:
#!/bin/bash
# test-string: evaluate the value of a string
ANSWER=maybe
if [ -z "$ANSWER" ]; then
echo "There is no answer." >&2
exit 1
fi
if [ "$ANSWER" = "yes" ]; then
echo "The answer is YES."
elif [ "$ANSWER" = "no" ]; then
echo "The answer is NO."
elif [ "$ANSWER" = "maybe" ]; then
echo "The answer is MAYBE."
else
echo "The answer is UNKNOWN."
fi*整型表達式integer1 -eq integer2:integer1 等於 integer2
integer1 -ne integer2:integer1 不等於 integer2
integer1 -le integer2:integer1 小於或等於 integer2
integer1 -lt integer2:integer1 小於 integer2
integer1 -ge integer2:integer1 大於或等於 integer2
integer1 -gt integer2:integer1 大於 integer2
*整型表達式例子:
#!/bin/bash
# test-integer: evaluate the value of an integer.
INT=-5
if [ -z "$INT" ]; then
echo "INT is empty." >&2
exit 1
fi
if [ $INT -eq 0 ]; then
echo "INT is zero."
else
if [ $INT -lt 0 ]; then
echo "INT is negative."
else
echo "INT is positive."
fi
if [ $((INT % 2)) -eq 0 ]; then
echo "INT is even."
else
echo "INT is odd."
fi
fi更現代的測試版本*目前的 bash 版本包含一個復合命令:[[ expression ]],與test相比增加了一個重要的新的字符串表達式:string1 =~ regex,若string1匹配擴展的正則表達式 regex則返回真
例子:
#!/bin/bash
# test-integer2: evaluate the value of an integer.
INT=-5
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
if [ $INT -eq 0 ]; then
echo "INT is zero."
else
if [ $INT -lt 0 ]; then
echo "INT is negative."
else
echo "INT is positive."
fi
if [ $((INT % 2)) -eq 0 ]; then
echo "INT is even."
else
echo "INT is odd."
fi
fi
else
echo "INT is not an integer." >&2
exit 1
fi*為整數設計的復合命令:(( ))例子:
#!/bin/bash
# test-integer2a: evaluate the value of an integer.
INT=-5
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
if ((INT == 0)); then
echo "INT is zero."
else
if ((INT < 0)); then
echo "INT is negative."
else
echo "INT is positive."
fi
if (( ((INT % 2)) == 0)); then
echo "INT is even."
else
echo "INT is odd."
fi
fi
else
echo "INT is not an integer." >&2
exit 1
fi通過使用邏輯操作符來結合表達式操作符測 試[[ ]] 和 (( ))AND-a&&OR-o||NOT!!控制操作符:分支的另一種方法*bash 支持兩種可以執行分支任務的控制操作符。這個 &&(AND)和||(OR)操作符作用如同復合命令[[ ]]中的邏輯操作符
*語法:command1 && command2 和 command1 || command2
*對於 && 操作符,只有當command1 執行成功後,才會執行 command2。對於 || 操作符,只有當command1 執行失敗後, 才會執行command2
*例如:
$ mkdir temp && cd temp :在成功創建目錄temp後跳轉到temp
$ [ -d temp ] || mkdir temp :若目錄 temp 不存在則創建這個目錄
[ -d temp ] || exit 1 : 若目錄temp不存在則返回退出狀態1
六、讀取鍵盤輸入(交互)read - 從標准輸入讀取單行數據
*語法形式:read [-options] [variable...]
*讀取一個整數:
echo -n "Please enter an integer -> " read var echo "var = '$var'"*給多個變量賦值:
echo -n "Enter one or more values > " read var1 var2 echo "var1 = '$var1'" echo "var2 = '$var2'"*若沒有提供變量名,shell 變量 REPLY 會包含數據行
echo -n "Enter one or more values > " read echo "REPLY = '$REPLY'"*read選項
-a array:把輸入賦值到數組 array 中,從索引號零開始
-d delimiter:用字符串 delimiter 中的第一個字符指示輸入結束,而不是一個換行符
-e:使用 Readline 來處理輸入。這使得與命令行相同的方式編輯輸入
-n num:讀取 num 個輸入字符,而不是整行
-p prompt:為輸入顯示提示信息,使用字符串 prompt
-r:Raw mode. 不把反斜槓字符解釋為轉義字符
-s:Silent mode. 不會在屏幕上顯示輸入的字符。當輸入密碼和其它確認信息的時候,這會很有幫助
-t seconds:超時. 幾秒鐘後終止輸入。read 會返回一個非零退出狀態,若輸入超時
-u fd:使用文件描述符 fd 中的輸入,而不是標准輸入
*read選項例子:
#!/bin/bash
if read -t 10 -sp "Enter secret pass phrase > " secret_pass; then
echo -e "\nSecret pass phrase = '$secret_pass'"
else
echo -e "\nInput timed out" >&2
exit 1
fi*此腳本提示用戶輸入一個密碼,若在10秒內沒有完成輸入,則腳本會退出並返回一個錯誤。因包含了一個 -s 選項,所以輸入的密碼不會出現在屏幕上。校正輸入*校正各種輸入的示例程序:
#!/bin/bash
invalid_input () {
echo "Invalid input '$REPLY'" >&2
exit 1
}
read -p "Enter a single item > "
# input is empty (invalid)
[[ -z $REPLY ]] && invalid_input
# input is multiple items (invalid)
(( $(echo $REPLY | wc -w) > 1 )) && invalid_input
# is input a valid filename?
if [[ $REPLY =~ ^[-[:alnum:]\._]+$ ]]; then
echo "'$REPLY' is a valid filename."
if [[ -e $REPLY ]]; then
echo "And file '$REPLY' exists."
else
echo "However, file '$REPLY' does not exist."
fi
# is input a floating point number?
if [[ $REPLY =~ ^-?[[:digit:]]*\.[[:digit:]]+$ ]]; then
echo "'$REPLY' is a floating point number."
else
echo "'$REPLY' is not a floating point number."
fi
# is input an integer?
if [[ $REPLY =~ ^-?[[:digit:]]+$ ]]; then
echo "'$REPLY' is an integer."
else
echo "'$REPLY' is not an integer."
fi
else
echo "The string '$REPLY' is not a valid filename."
fi菜單,一種常見的交互類型稱為菜單驅動*菜單驅動例子
#!/bin/bash
# read-menu: a menu driven system information program
clear
echo "
Please Select:
1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0. Quit
"
read -p "Enter selection [0-3] > "
if [[ $REPLY =~ ^[0-3]$ ]]; then
if [[ $REPLY == 0 ]]; then
echo "Program terminated."
exit
fi
if [[ $REPLY == 1 ]]; then
echo "Hostname: $HOSTNAME"
uptime
exit
fi
if [[ $REPLY == 2 ]]; then
df -h
exit
fi
if [[ $REPLY == 3 ]]; then
if [[ $(id -u) -eq 0 ]]; then
echo "Home Space Utilization (All Users)"
du -sh /home/*
else
echo "Home Space Utilization ($USER)"
du -sh $HOME
fi
exit
fi
else
echo "Invalid entry." >&2
exit 1
fi*從邏輯上講,這個腳本被分為兩部分。第一部分顯示菜單和用戶輸入。第二部分確認用戶反饋,並執行 選擇的行動參考:《The Linux Command Line》