Scripting
腳本¶
環境¶
在執行中,shell會透過PATH環境變量來尋找指令,有兩種方法可以解決找不到命令的問題
- 將shell腳本放到
PATH環境變量中 - 利用相對或絕對路徑來引用腳本
echo顯示訊息,可以使用單引號'或雙引號"界定字符串-n將字符串與命令顯示在同一列中
$引用環境變量- 反斜線
\允許shell腳本按照字面顯示$
- 反斜線
自定義變量¶
- shell允許用戶在腳本中自定義和使用自己的變量,但變量、等號與值中間 不能有空格
- 引用變量時加$,對變量賦值時不用加
-
從命令輸出中提取訊息並賦予變量
(``)反引號$()格式 若date為命令,則
輸出日期例子
#!/bin/bash #copy the /usr/bin directory listing to a log file today=$(date +%y%m%d) ls /usr/bin -al > log.$today注意:命令替換子shell中執行,無法使用腳本中的變量,但如果以不加路徑的方式執行則不會創建子shell
基本操作¶
-
>,>>,<將命令作為輸入/輸出 -
|:將命令傳給另一個命令,這個過程稱為 piping -
EOF:定義了重定向數據的起止 -
$?:linux提供的專門變量,用來保存最後一個已執行命令的退出狀態碼一般狀態碼定義如下
狀態碼 描述 0 命令成功結束 1 一般未知錯誤 2 不適合的shell命令 126 命令無法執行 127 沒找到命令 128 無效的退出參數 128+x 與linux信號x相關的嚴重錯誤 130 透過 ctrl + c終止的命令255 正常範圍以外的退出狀態碼 -
exit默認狀態下,以腳本最後一個命令的退出狀態碼退出,也可以自己指定退出狀態碼
使用時,記得退出最大狀態碼僅有255,超過會以255的餘數作為回傳值
-
將標準輸出與標準錯誤訊息重定向(&>)至/dev/null被稱為黑洞,送往這的東西都會有去無回 查看下列程式碼/dev/null,使腳本輸出簡潔許多 > 注意:&>會重定向標準輸出與標準錯誤,而>僅重定向標準輸出 -
/dev/zero充滿著無限個0 bit的文件
數學運算¶
expr命令:最一開始的數學表達式命令,但也特別笨拙- 方括號
[]:更簡單的方法執行數學運算 要將數學運算賦給變量,可以使用$與[]:var=$[operation]> bash shell一般只支援整數運算
浮點數¶
bc:bash 計算器實際上是一種編程語言,允許在命令行輸入浮點數表達
運算需要先設置scale,顯示小數點後幾位,預設為0
* quit:離開bc
在腳本中使用bc的方法為$ variable=$(echo "options; expression" | bc)
in shell script
EOF字符串標定了重定向給bc命令的起止
條件控制¶
if-then-else語句¶
bash語句會執行if之後的命令,如果該命令的退出狀態碼為0,位於then的命令才會執行
透過把分號(;)放在代求值的命令尾部,可以將
if-then腳本有另一種形式then語句寫在同一行 緊跟在elif後的else是屬於elif的,不屬於之前的if-then語句
test命令 test命令可以在if-then語句中測試不同的條件,如果test中的條件成立,其會退出並返回狀態0 格式如下:test conditioncondition是test要測試的一系列參數與值,用在if-then時會看起來如下- bash shell提供另一種條件測試方式,使用
[]替代test命令注意 :第一個方括號之後與第二個方括號之前 必須 留有空格
測試可以判斷3種條件
- 數值比較
- 字符串比較
- 文件比較
數值比較¶
| 比較 | 描述 |
|---|---|
| n1 -eq n2 | 檢查 n1 是否等於 n2 |
| n1 -ge n2 | 檢查 n1 是否大於或等於 n2 |
| n1 -gt n2 | 檢查 n1 是否大於 n2 |
| n1 -le n2 | 檢查 n1 是否小於或等於 n2 |
| n1 -lt n2 | 檢查 n1 是否小於 n2 |
| n1 -ne n2 | 檢查 n1 是否不等於 n2 |
字符串比較¶
| 比較 | 描述 |
|---|---|
| str1 = str2 | 檢查 str1 與 str2 是否相同 |
| str1 != str2 | 檢查 str1 與 str2 是否不同 |
| str1 < str2 | 檢查 str1 是否小於 str2 |
| str1 > str2 | 檢查 str1 是否大於 str2 |
| -n str1 | 檢查 str1 的長度是否不為0 |
| -z str2 | 檢查 str1 的長度是否為0 |
在比較大小時,是使用每個字符的Unicode編碼值
使用
>與<時必須轉義,否則shell會將其視為重定義符,將字串當作文件名
要解決這問題,需要使用反斜線( )正確轉義
文件比較¶
這些測試條件允許在shell腳本中檢查文件系統的文件
| 比較 | 描述 |
|---|---|
| -d file | 檢查 file 是否存在且為目錄 |
| -e file | 檢查 file 是否存在 |
| -f file | 檢查 file 是否存在且為文件 |
| -r file | 檢查 file 是否存在且可讀 |
| -s file | 檢查 file 是否存在且非空 |
| -w file | 檢查 file 是否存在且可寫 |
| -x file | 檢查 file 是否存在且可執行 |
| -O file | 檢查 file 是否存在且屬當前用戶所有 |
| -G file | 檢查 file 是否存在且默認組與當前用戶相同 |
| file1 -nt file2 | 檢查 file1 是否比 file2 新 |
| file1 -ot file2 | 檢查 file1 是否比 file2 舊 |
1. 檢查目錄
-d會檢查指定目錄是否存在系統中,在文件寫入前或是切換到某目錄,先測試一下總是好事
jump_dir=/home/Torfa
if [ -d $jump_dir ]
then
echo "dir exist, jump to target"
cd jump_dir
else
echo "dir not exist"
fi
2. 檢查對象是否存在
-e允許在使用文件或目錄前檢查其是否存在
file_name="sofa"
if [ -e $jump_dir/$filename ]
then
echo "ok on the file, uploading content"
date >> $jump_dir/$filename
else
echo "file not found"
fi
3. 檢查文件
確定指定目標為文件,就必須使用-f測試
-r確認文件是否可讀
pwfile=/etc/shadow
if [ -r $pwfile]
then
echo "Displaying end of file"
tail $pwfile
else
echo "sorry, the $pwfile file does not exist"
fi
5. 檢查空文件 檢查文件是否為空,尤其是當你不想刪除非空文件時
file_name=$HOME/sentinel
if [ -s $file_name ]
then
echo "the $file_name file has data in it"
else
echo "the $file_name file is empty"
fi
6. 檢查是否可寫
-w檢查文件是否可寫
7. 檢查是否可執行
-x檢查文件是否可寫
8. 檢查所有權
-O檢查執行者是否為文件屬主
複合條件¶
if-then語句允許使用布林邏輯將測試條件組合起來
* [ condition1 ] && [ condition2 ]
* [ condition1 ] || [ condition2 ]
使用單括號¶
單括號 ( )允許if語句中使用子shell,使用格式(command),在bash shell執行command前,會先創建子shell,成功結束則返回0
當在
if-then中使用進程列表,可能會出現意料之外的結果,哪怕進程列表最後一個命令以外的其他命令全失敗,子shell仍會返回0
使用雙括號¶
雙括號 命令允許在比較過程中使用高級數學表示式(基本上跟C++相同)
使用雙方括號¶
雙方括號 命令提供了針對字符串比較的高級特性
雙方括號在bash中運行良好,但要注意不是所有的shell都支援雙方括號
case 命令¶
有了case命令,就無需再寫大量的if-elif-else語句,case會採用列表格式來檢查變量的多個值
case $USER in
rich | christime)
echo "Welcome $USER"
echo "Please enjoy your visit";;
babara | tim)
echo "Hi there";;
testing)
echo "log out when you're done";;
*)
echo "you're not belong here";;
esac
for命令¶
最基本的用法是遍歷自身定義的一系列值
在最後一次迭代之後,$test變量仍然有效
shell會將列表值中的單引號作為單獨數據,若僅想使用單引號'在列表內,可以使用雙引號"來定義含有單引號的值
for循環假設定義各個值之間是以 空格 分隔的
從變量中讀取值列表¶
把變量帶入in後面就好
從命令中讀取值列表¶
使用命令輸出,並在for迴圈內使用
遍歷目錄¶
for file in /home/rich/test/* /home/rich/other_test/*
do
if[ -d "$file" ]
then
echo "$file is a directory"
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done
在linux中,目錄名和文件名包含空格是合法的,要在shell script裡實現,應將 $file 變量加入雙引號內
C語言風格的for loop¶
基本格式如下
- 變量賦值可以有空格
- 迭代條件的變量不以美元符號開頭
- 迭代過程的算式不使用
expr命令格式
Ex
for 命令也允許可以使用多個變量更改分隔符號¶
IFS(Internal field separator)環境變量定義了bash shell用作字段分隔符的一系列字元,默認情況下,bash shell會將下列文字作為分隔符號
- 空格
- 制表符號
- 換行符號
若要更改IFS環境變量,使bash shell能識別換行符號
將該語句加入腳本,bash shell便會忽略數據中的空格與制表符 如果要遍歷文件中以冒號分隔的值,只需將IFS設為冒號即可 如果要指定多個IFSwhile 命令¶
格式如下
例子使用多個測試命令¶
在有多個命令的while語句中,每次迭代時的所有測試命令都會被執行,包括最後一個測試失敗末次迭代
until命令¶
與while相反,until會持續執行直到測試命令的退出狀態碼不為0
break¶
break可以退出當前正在執行的循環
break命令接受單個命令參數n,指定退出的循環
continue¶
continue
提前結束某次循環
處理循環的輸出¶
for file in /home/rich/*
do
if [ -d "$file" ]
echo "$file is a directory"
elif [ -f "$file" ]
echo "$file is a file"
fi
done > output.txt
output.txt中
sed 與 awk¶
處理文件的工具
sed¶
sed被稱為 流編輯器 (stream editor),可以執行以下動作
- 從輸入中讀取一行數據
- 根據提供的編輯器命令匹配參數
- 按照命令修改數據流中的數據
- 將新數據輸出到STDOUT
命令格式如下
* options *-e command : 處理輸入時,加入額外的sed命令
* -f file:處理輸入時,將file中指定的命令添加到已有的命令中
* -n:不產生命令輸出,使用p (print)命令完成輸出
在命令中定義編輯器命令
s替換命令用斜線間指定的第二個字符串替換第一個字符串
sed命令並不會修改文本文件的數據
gawk¶
在gawk中,可以實現以下操作
- 定義變量來保存數據
- 使用算術與字符串來處理數據
- 使用if-then與loop等邏輯處理數據
- 提取文件的數據並重新排列組合
命令格式如下
- options
-F fs:指定行中劃分數據分段的分隔符-f file:從指定文件中讀取gawk腳本代碼-v var=value:定義gawk腳本中的變量及默認值-L [keyword]:指定gawk的兼容模式
需要把gawk命令腳本放到單引號內
gawk程序,需要使用Ctrl+D生成EOF字符