以下內容為本人的學習筆記,如需要轉載,請宣告原文連結 微信公眾號「englyf」https://www.cnblogs.com/englyf/p/16721350.html
從頭一二去閱讀語法和命令說明,對於指令碼小白來說比較枯燥,難以堅持,所以這裡選擇對一份完整的shell指令碼程式碼來逐行逐段解讀,希望可以一渡小白,幫助我們快速進入指令碼的大門_。
司機要開車了:
#!/bin/sh
用註釋的形式說明檔案開啟型別,此處意指本指令碼需要用 /bin/sh 開啟。
#V1.0 Added hardware type detection
#V1.1 xxxx-xx-xx 重構指令碼
#V1.2 xxxx-xx-xx 將紀錄檔資訊輸出到U盤
#V1.3 xxxx-xx-xx 讀取儲存的檢測結果值
#V1.4 xxxx-xx-xx 新增校驗程式版本,U盤下有對應版本資訊檔案才校驗
上面幾行表示註釋內容。單行註釋,以#
開始
UDiskMountDir=$(df | grep /mnt/sd | awk 'END{print $NF}')
宣告變數 UDiskMountDir 並賦值。
$()
括號內填入命令並執行,最後返回輸出到變數 UDiskMountDir。
df
命令顯示liinux系統上的檔案系統磁碟使用情況統計。後邊還可以帶選項,執行更復雜的輸出。命令後邊加 '|' 表示將此命令的輸出作為後邊緊接著的命令的輸入。
grep
命令用於對文字按行搜尋然後輸出該行。英文全稱 global search regular expression(RE) and print out the line。grep /mnt/sd
表示搜尋輸入資訊裡包含 /mnt/sd
的一行,並輸出該行。
awk
命令用於對文書處理,END
表示執行最後的運算或者列印最終的輸出結果,這裡用於列印輸出,$NF
表示列數,print $NF
表示列印最後一個欄位,各個欄位預設以空格劃分,可用選項 -F
指定使用什麼字串來劃分。
LogFile=${UDiskMountDir}/Debug.log
宣告變數 LogFile 並以右邊的內容賦值。將變數 UDiskMountDir 所代表的路徑名與後邊的字串結合為新的檔名。一般命令中用到的檔名,要不是帶相對路徑的檔名,如 ./diretion/filename
,就是帶絕對路徑的檔名,如 /root/diretion/filename
。
${UDiskMountDir}
表示參照變數 UDiskMountDir 的值。
AllCheckPassed=true
宣告變數 AllCheckPassed 並賦值為true。
AddError()
{
AllCheckPassed=false
echo "-200" > /tmp/VerCheckRes
}
宣告函數 AddError,輸入引數無需宣告。
變數 AllCheckPassed 賦值為true。
echo
命令用於輸出字串。echo "-200" > /tmp/VerCheckRes
將 -200 輸出到檔案 /tmp/VerCheckRes 並覆蓋原有內容。如果將符號 >
換成 >>
則是將內容追加到最後位置。
AddRecord()
{
if [ ! -d "/userdata/recordsDir/" ];then
mkdir -p /userdata/recordsDir/
fi
echo "$*" > /userdata/recordsDir/test
sync
AddDebugLog2UDisk $*
}
宣告函數 AddRecord。
if
表示 if 語句的開始。if[]
方括號內填判斷條件,如為 true 則執行 then 後的語句,否則跳出 if 語句。fi
表示 if 語句的結束。和 C 語言類似,if 語句也可以有 else
甚至 else if
(shell 內應該寫成 elif
)。if/elif
和 then
如果不在同一行則可以省略符號 ;
。if [ ! -d "/userdata/recordsDir/" ]
判斷目錄 /userdata/recordsDir/ 是否存在,並對結果值取反(!
)。
mkdir
命令用於構建目錄。帶選項 -p
表示構建路徑下所有的目錄。mkdir -p /userdata/recordsDir/
建立目錄 /userdata/recordsDir/, /userdata/ 如果不存在也會被構建。
echo "$*" > /userdata/recordsDir/test
將函數輸入的所有引數都輸出到檔案 '/userdata/recordsDir/test' 並覆蓋原有內容。'$*' 表示當前函數或者指令碼的所有輸入引數,由於在函數內參照,所以這裡表示函數的所有輸入引數。
sync
命令用於資料同步。Linux 系統中寫入硬碟的資料往往會被先存放於 buffer 中,這樣是為了效率起見,但是如果系統突然斷電,那麼資料就會丟失,這時可以呼叫 sync 將 buffer 中的資料同步到硬碟。
AddDebugLog2UDisk $*
呼叫函數 AddDebugLog2UDisk 並傳入當前函數(AddRecord)的所有引數。
AddDebugLog2UDisk()
{
echo "$*" >>"$LogFile"
sync
}
宣告函數 AddDebugLog2UDisk。
echo "\$*" >>"$LogFile"
表示將函數的所有輸入引數輸出到變數 LogFile 表示的檔案中,以追加的形式輸入到檔案末尾。
sync
同步資料到硬碟。
#生成下/tmp/App/version.txt版本資訊
註釋內容
rm -f "$LogFile"
rm
命令用於移除檔案。選項 -f
表示強制。rm -f "$LogFile"
強制移除變數 LogFile 代表的檔案,變數 LogFile 儲存的是檔名,包括路徑。
echo "0" > /tmp/VerCheckRes
輸出字串 '0' 到檔案 /tmp/VerCheckRes
sh /data/bin/run_normal.sh
在當前的環境中使用另一個shell來執行指令碼檔案 /data/bin/run_normal.sh,當前環境中變數的值可以在新指令碼(/data/bin/run_normal.sh)中被使用(非參照,如果使用 source則變為參照),新指令碼檔案屬性可以無執行許可權。sh
後邊可以帶選項 -n
、-x
等,-n
用於進行shell指令碼的語法檢查,-x
用於實現shell指令碼的逐句跟蹤偵錯並列印該行命令和狀態等。
sleep 2
阻塞當前程序,睡眠 2 秒,和 sleep 2s
同樣效果。sleep 2h
表示睡眠 2 小時。
sh /tmp/App/kill.sh
執行指令碼檔案 /tmp/App/kill.sh
killall MachineCheckNode
殺掉程序 MachineCheckNode,MachineCheckNode 為程序名。
lastSNScanResult=$(cat /userdata/recordsDir/scan)
讀取檔案 /userdata/recordsDir/scan 內容並賦值給變數 lastSNScanResult。
cat
命令用於連線檔案並輸出內容到標準輸出。
AddDebugLog2UDisk "last sn scan result:$lastSNScanResult"
呼叫函數 AddDebugLog2UDisk,並傳遞字串 last sn scan result:$lastSNScanResult
,$lastSNScanResult
獲取變數 lastSNScanResult 的值然後和前面的字串結合成新的字串。
#檢查SN和markData
if [ ! -f /data/bin/sysData/sn ]; then
AddRecord "sn missing"
AddError
else
snContent=$(cat /data/bin/sysData/sn)
AddRecord "sn is:$snContent"
snLen=$(cat /data/bin/sysData/sn | awk '{print length($0)}')
if [ "$snLen" != "16" ] ; then
AddRecord "sn length error $snLen"
AddError
fi
fi
if [ ! -f /data/bin/sysData/sn ]
判斷檔案 /data/bin/sysData/sn 是否是常規檔案而且存在,'!' 表示對結果值取反。
如果檔案 /data/bin/sysData/sn 找不到或者不是常規檔案,則呼叫後邊的語句塊,直到 else 為止。呼叫函數 AddRecord(傳入字串 "sn missing") 和 AddError(無引數傳入)。
否則,獲取檔案內容並賦值給變數 snContent,呼叫函數 AddRecord(輸入 sn is:$snContent", 字串其中會插入變數 snContent 的值);宣告變數 snLen,賦值為命令 cat /data/bin/sysData/sn | awk '{print length($0)}'
的執行結果;判斷 snLen 是否不等於 16,是則呼叫函數 AddRecord 和 AddError。
$(cat /data/bin/sysData/sn | awk '{print length($0)}')
讀取檔案 /data/bin/sysData/sn 的內容,通過管道('|')輸入到後一命令語句,awk 計算輸入內容的第一欄位的字元長度並輸出。
if [ ! -f /data/bin/sysData/markData ]; then
AddRecord "markData missing"
AddError
fi
判斷檔案 /data/bin/sysData/markData 是否不存在,不存在則呼叫後邊的語句(以 fi 為止)。
#檢驗版本資訊
while read -r line || [ -n "${line}" ]; do
[ "$line" = "" ] && continue
item_filename=$(echo "$line" | awk -F":" '{print $1}')
item_filemd5=$(echo "$line" | awk -F":" '{print $2}')
if [ ! -e "$item_filename" ]; then
AddRecord "$item_filename missing"
AddError
fi
acture_md5=$(md5sum "$item_filename" | awk '{print $1}')
if [ "$item_filemd5" = "$acture_md5" ]; then
continue
else
AddRecord "$item_filename" "md5 diff! file:" "$item_filemd5" "acture:" "$acture_md5"
AddError
fi
done </tmp/MachineDecDir/check_md5list
while read xxx; do
...
done </filename
迴圈讀取檔名 filename 所指向的檔案的內容,每讀取一行存入 xxx 變數。read xxx
為 while 語句的判斷語句,判斷語句和 do
如果不在同一行,則 ;
可省略,如:
while read xxx
do
...
done </filename
read 後邊的 -r
表示讀取內容過程中對特殊字元有效,如 /
(輸入未結束需要換行繼續輸入的特殊符號),'/n' 等等。
[ -n "${line}" ]
判斷 line 的內容不為空。而前邊的 '||' 表示前一語句 read -r line
返回 false 才執行這個語句。
[ "$line" = "" ] && continue
表示如果 line 的內容為空則執行 continue;continue 命令用於跳過當前回圈內容回去執行 while 判斷語句。
item_filename=$(echo "$line" | awk -F":" '{print $1}')
宣告變數 item_filename 並以後邊語句執行結果賦值。awk -F":" '{print $1}')
將輸入的內容按照 :
來劃分欄位並輸出第1個欄位。awk -F":" '{print $2}')
則是將輸入的內容按照 ':' 來劃分欄位並輸出第2個欄位。
if [ ! -e "$item_filename" ]
用於判斷變數 item_filename 代表的檔名所指的檔案是否不存在。!
表示取反。if 判斷的內容為 true 則執行 then 後邊的語句,直到 fi 為止,否則跳過。
md5sum "$item_filename"
表示計算變數 item_filename 代表的檔名所指的檔案的MD5值。
| awk '{print $1}'
將前一語句的輸出通過管道連線到後邊的這個語句的輸入,預設按照空格劃分內容並輸出第1個欄位內容。
if [ "$item_filemd5" = "$acture_md5" ]; then
判斷 item_filemd5 和 acture_md5 所代表的內容作為字串是否一樣,是則執行 then 後的語句。continue 指示程式執行流程直接回到執行 while 判斷語句。else 後的語句塊當 if 的判斷條件不為 true 時執行。
#找到 U 盤路徑
UDiskMountDir=$(df | grep /mnt/sd | awk 'END{print $NF}')
#校驗mcu程式版本,U盤下有mcuversion.txt才校驗
UDiskMountDirfile="${UDiskMountDir}/SpecialDir/mcuversion.txt"
CurMcuVersionFile="/tmp/mcuversion.txt"
if [ -f "$UDiskMountDirfile" ]; then
TargetMcuVersion=$(cat "$UDiskMountDirfile")
if [ -f "$CurMcuVersionFile" ]; then
CurMcuVersion="$(cat "$CurMcuVersionFile")"
if [ "$TargetMcuVersion" != "$CurMcuVersion" ]; then
AddRecord "mcuversion diff cur:$CurMcuVersion target:$TargetMcuVersion"
AddError
fi
else
AddRecord "$CurMcuVersionFile not found"
AddError
fi
fi
UDiskMountDirfile="${UDiskMountDir}/SpecialDir/mcuversion.txt"
宣告變數 UDiskMountDirfile 並賦值為其後的內容,其後是將變數 UDiskMountDir 所代表的路徑名與後邊的字串結合為新的檔名。
if 語句可以有多重巢狀,如上。
[ "$TargetMcuVersion" != "$CurMcuVersion" ]
判斷 TargetMcuVersion 和 CurMcuVersion 所代表的內容是否不相等。
#寫入檢查結果
if [ $AllCheckPassed = "true" ]; then
AddRecord "Pass"
else
AddRecord "Fail"
fi
if [ $AllCheckPassed = "true" ]; then
判斷 AllCheckPassed 的值是否等於字串 "true",是則呼叫函數 AddRecord 並傳入引數字串 "Pass",否則呼叫函數 AddRecord 並傳入引數字串 "Fail"。
#啟動checkall
/data/bin/Factory/MachineCheckNode MachineImcomingTest
呼叫絕對路徑下的程式 MachineCheckNode,並傳入字串引數 MachineImcomingTest。此種呼叫方式,要求程式檔案 MachineCheckNode 具有可執行的許可權屬性x。想要檢視指定路徑下所有檔案或某個檔案的屬性可以使用命令 ls -l
檢視,r
表示可讀,w
表示可寫,x
表示可執行。
username@DESKTOP-ABCDEF:/mnt/d/username/work/temp$ ls -l
total 0
drwxrwxrwx 1 username username 4096 May 21 16:10 Udisk_IQC
這篇講解到此為止,下期再見!