嘗試閱讀理解一份linux shell腳本

来源:https://www.cnblogs.com/englyf/archive/2022/09/23/16721350.html
-Advertisement-
Play Games

從頭一二去閱讀語法和命令說明,對於腳本小白來說比較枯燥,難以堅持,所以這裡選擇對一份完整的shell腳本代碼來逐行逐段解讀,希望可以一渡小白,幫助我們快速進入腳本的大門^_^ ...


以下內容為本人的學習筆記,如需要轉載,請聲明原文鏈接 微信公眾號「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/elifthen 如果不在同一行則可以省略符號 ;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表示可執行。

[email protected]:/mnt/d/username/work/temp$ ls -l
total 0
drwxrwxrwx 1 username username 4096 May 21 16:10 Udisk_IQC

這篇講解到此為止,下期再見!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 17.1遠程資源授權準備 17.1.1認證和訪問流程圖 參考:http://www.zyiz.net/tech/detail-141309.html 17.1.2為用戶指定角色 可以使用ROLE_USER和ROLE_ADMIN 兩種角色 17.1.3添加認證服務和資源服務 17.1.4配置客戶端的認 ...
  • 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> OpenGL ES 特效 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> O ...
  • “為什麼加索引能提升查詢效率”! 我們都認為“加索引”提升查詢效率是理所應當的 竟然還有理由? 該怎麼回答呢? 大家好,我是Mic,一個工作了14年的Java程式員 下麵分析一下這個問題的考察點 考察目標 這是一道原理性的問題,考察求職者對於Mysql中索引的實現原理的理解程度。 一般情況下,考察3 ...
  • 摘要:java中一切都是對象,為什麼int不用創建對象實例化,而可以直接使用? 本文分享自華為雲社區《【Java】對基本類型-整型數據結構的認識》,作者: huahua.Dr 。 整型數據類型有兩個:基本類型和引用類型(包裝類) 整數型基本類型:byte,int,short,long 其引用類型:B ...
  • 一、插入排序 1、直接插入排序 基本思想:類似抓撲克牌,待排序元素在已排序的序列中從後往前遍歷,遇到小於他的元素向後移一位,直至遇到小於或等於他的元素,在其後插入即可 2、希爾排序(是對直接插入排序的一種改進) 二、交換排序 1、冒泡排序 基本思想:相鄰的兩個元素進行兩兩比較,如果出現逆序,則小的元 ...
  • 前言 本次案例最終實現效果 開發環境 python 3.8: 解釋器 pycharm: 代碼編輯器 界面代碼實現 先導入所需模塊 import tkinter as tk from tkinter import ttk import tkinter.messagebox 創建視窗 root = tk ...
  • 一:背景 1. 講故事 其實這個問題是前段時間有位朋友咨詢我的,由於問題說的比較泛,不便作答,但想想梳理一下還是能回答一些的,這篇就來聊一聊下麵這幾個鎖。 Interlocked AutoResetEvent / ManualResetEvent Semaphore 用戶態層面我就不想說了,網上一搜 ...
  • .NET運行時之書(Book of the Runtime,簡稱BotR)是一系列描述.NET運行時的文檔,2007年左右在微軟內部創建,最初的目的為了幫助其新員工快速上手.NET運行時;隨著.NET開源,BotR也被公開了出來,如果你想深入理解CLR,這系列文章你不可錯過。 BotR系列目錄: [ ...
一周排行
    -Advertisement-
    Play Games
  • Github / Gitee QQ群(1群) : 813100564 / QQ群(2群) : 579033769 視頻教學 介紹 MiniWord .NET Word模板引擎,藉由Word模板和數據簡單、快速生成文件。 Getting Started 安裝 nuget link : https:// ...
  • Array.Sort Array類中相當實用的我認為是Sort方法,相比起冗長的冒泡排序,它的出現讓排序更加的簡化 結果如下: 還可以聲明一個靜態方法用來專門調用指定數組排序,從名為 array 的一維數組中 a 索引處開始,到 b 元素 從小到大排序。 註意: a + b 不能大於 array 的 ...
  • 前言 在上一篇文章CLR類型系統概述里提到,當運行時掛起時, 垃圾回收會執行堆棧遍歷器(stack walker)去拿到堆棧上值類型的大小和堆棧根。這裡我們來翻譯BotR里一篇專門介紹Stackwalking的文章,希望能加深理解。 順便說一句,StackWalker在中文里似乎還沒有統一的翻譯,J ...
  • 使用過 nginx 的小伙伴應該都知道,這個中間件是可以設置跨域的,作為今天的主角,同樣的 反向代理中間件的 YARP 毫無意外也支持了跨域請求設置。 有些小伙伴可能會問了,怎樣才算是跨域呢? 在 HTML 中,一些標簽,例如 img、a 等,還有我們非常熟悉的 Ajax,都是可以指向非本站的資源的 ...
  • 什麼是Git Git 是一個開源的分散式版本控制系統,用於敏捷高效地處理任何或小或大的項目。 Git 是 Linus Torvalds 為了幫助管理 Linux 內核開發而開發的一個開放源碼的版本控制軟體。 Git 與常用的版本控制工具 CVS, Subversion 等不同,它採用了分散式版本庫的 ...
  • 首先CR3是什麼,CR3是一個寄存器,該寄存器內保存有頁目錄表物理地址(PDBR地址),其實CR3內部存放的就是頁目錄表的記憶體基地址,運用CR3切換可實現對特定進程記憶體地址的強制讀寫操作,此類讀寫屬於有痕讀寫,多數驅動保護都會將這個地址改為無效,此時CR3讀寫就失效了,當然如果能找到CR3的正確地址... ...
  • 說明 onlyoffice為一款開源的office線上編輯組件,提供word/excel/ppt編輯保存操作 以下操作均基於centos8系統,officeonly鏡像版本7.1.2.23 鏡像下載地址:https://yunpan.360.cn/surl_y87CKKcPdY4 (提取碼:1f92 ...
  • 二叉樹查找指定的節點 前序查找的思路 1.先判斷當前節點的no是否等於要查找的 2.如果是相等,則返回當前節點 3.如果不等,則判斷當前節點的左子節點是否為空,如果不為空,則遞歸前序查找 4.如果左遞歸前序查找,找到節點,則返回,否繼續判斷,當前的節點的右子節點是否為空,如果不為空,則繼續向右遞歸前 ...
  • ##Invalid bound statement (not found)出現原因和解決方法 ###前言: 想必各位小伙伴在碼路上經常會碰到奇奇怪怪的事情,比如出現Invalid bound statement (not found),那今天我就來分析以下出現此問題的原因。 其實出現這個問題實質就是 ...
  • ###一、背景知識 爬蟲的本質就是一個socket客戶端與服務端的通信過程,如果我們有多個url待爬取,只用一個線程且採用串列的方式執行,那隻能等待爬取一個結束後才能繼續下一個,效率會非常低。 需要強調的是:對於單線程下串列N個任務,並不完全等同於低效,如果這N個任務都是純計算的任務,那麼該線程對c ...