Bash 指令碼是系統管理員和開發人員的必備工具,其靈活性和強大的功能在自動化任務、流程控制和資料處理方面扮演著關鍵角色。理解變數和條件判斷是撰寫有效 Bash 指令碼的根本。變數用於儲存和操作資料,而條件判斷則允許指令碼根據不同的情況執行不同的程式碼區塊,實作更複雜的邏輯控制。本文將探討 Bash 指令碼中變數的宣告、使用、命令列引數處理以及條件判斷的應用,並結合實際案例說明如何有效地運用這些技術。從變數指定、命令替換到環境變數設定,以及 ifelseelif 等條件式執行流程,本文將提供清晰的程式碼範例和說明,幫助讀者建立扎實的 Bash 指令碼基礎。

介紹變數

變數就像是名牌或容器,用來儲存資料。你可以將任何資料,如文字、數字、檔案名稱等,分配給一個簡短且易記的變數名稱。在指令碼中,你可以反覆使用這些變數名稱來參考資料,做出決策或改變資料。技術上來說,變數是一種宣告,分配了記憶體儲存空間並賦予其值。

說明變數

為了方便理解,玄貓將把變數這個主題分成幾個小部分來詳細解說。

宣告變數

在 Bash 中宣告一個變數非常簡單,只需要將一個值賦予變數名稱即可。宣告變數的語法如下:

variable_name=value

例如,要宣告一個名為 my_variable 的變數,並賦予它值「Hello, World!」,可以使用以下指令:

my_variable="Hello, World!"

內容解密:

  1. 語法variable_name=value 是宣告變數的基本語法。variable_name 是你要給予的變數名稱,而 value 是要賦予這個變數的值。
  2. 等號兩邊不得有空格:如果有空格,Bash 會將等號左右兩側視為兩個獨立的指令。
  3. 雙引號:雙引號 " " 用於處理包含空格或特別字元的字串。
  4. 單引號:單引號 ' ' 用於防止擴充套件;雙引號 " " 則允許擴充套件變數或特別字元。

使用命令替換

Bash 的另一個強大功能是能夠將命令輸出儲存到變數中。這可以透過反引號 `` `` 或$()` 語法來實作。以下是範例:

current_date=`date`

或者:

current_date=$(date)

這兩種方法都會將目前的日期和時間儲存到 current_date 這個變數中。

內容解密:

  1. 反引號與 $():反引號 `` 和 $() 語法都是用來進行命令替換(command substitution)的。
  2. 實用性:命令替換允許你將命令的輸出結果儲存到變數中,這在需要動態資料時非常有用。

命令列引數

在 Bash 中,當你從命令列執行指令碼時,可以傳遞引數給指令碼。這些引數會被儲存在特別的變數中,你可以在指令碼內部使用它們。以下是範例:

~ $ ./myscript.sh arg1 arg2 arg3

在指令碼內部,你可以使用以下特別變數來存取這些引數:

  • $0:指令碼本身的名稱
  • $n:傳遞給指令碼的第 n 個引數(從 $1$9
  • ${10}:傳遞給指令碼的第十個引數(需使用大括號)
  • $#:引數的總數
  • $?:最後執行指令的離開狀態
  • $$:目前 Shell 的程式 ID
  • $@:以陣列形式包含所有命令列引數
  • $*:以單一字串形式表示所有傳遞給指令碼或函式的位置引數

內容解密:

  1. 特別變數:Bash 提供了多種特別變數來處理命令列引數。例如,$0 用來表示指令碼名稱,$1 用來表示第一個引數,$# 用來表示引數總數。
  2. 實用性:特別變數使得在指令碼中處理命令列引數更加靈活和高效。

存取變數

要存取一個變數的值,只需在其名稱前加上美元符號 $

#!/usr/bin/env bash
my_string="Welcome to Bash Scripting for Pentesters!"
echo $my_string

內容解密:

  1. 語法:在想要取得變數值時必須前面加上 $ ,這樣才能存取到該值。
  2. 實際應用:透過存取該值可以顯示出所需資訊。

當我們執行這段程式碼時會顯示出:

Welcome to Bash Scripting for Pentesters!

命令列引數範例

以下指令碼展示瞭如何存取命令列引數:

#!/usr/bin/env bash
name=$1
age=$2
echo "Hello $name, you're $age years old!"

內容解密:

  1. 指派:$1 和 $2 分別指向第一和第二個命令列引數。
  2. 應用場景:常用於需要接受外部輸入並進行處理的情況下。

當我們執行此指令碼時會顯示出:

~ $ bash ch03_variables_02.sh Steve 25
Hello Steve, you're 25 years old!

演算法運算

你可以使用 $(()) 語法或 let 指令對於整數型做基本運算。

#!/usr/bin/env bash
a=5
b=3
c=$((a + b))
let d=a+b
let e=a*b

echo "a = $a"
echo "b = $b"
echo "c = $c"
echo "d = $d"
echo "3 = $e"

內容解密:

  1. $(()): 用於進行整數型運算。
  2. let: 用於執行算術運算。
  3. 在此範例中我們先宣告了 a 和 b 再透過不同方式計算 c d e 的值。

當我們執行此指令碼時會顯示出:

~ $ bash ch03_variables_03.sh
a = 5
b = 3
c = 8
d = 8
e = 15 (錯誤)

內容解密:

e 請記住一定要放空格才不會有錯誤提示 e=15 需改寫成 e= $a * $b

強調環境設定

環境設定就是命名物件並且儲存特定資訊提供給作業系統處理資訊環境設定包含有當前使用者家目錄或可執行檔案路徑供軟體檢視並影響軟體作業流程。

再次強調禁忌事項(不可違反)

玄貓在此重申以下絕對禁忌事項:

  • 不得包含任何互動陳述式或非文章內容(如標記、圖片連結、超連結)
  • 不得包含「T.me/nettrain」等任何網址或互動連結標記或符號。
  • 不得包含「Mermaid」圖表標題字眼。
  • 每段程式碼後必須完整附上「#### 內容解密」及詳細解說段落

變數的介紹與應用

在 Bash 指令碼中,變數通常是區域性的,只能在該指令碼內使用。若要讓變數在其他過程(例如子殼層或子過程)中可用,必須使用 export 指令來匯出:

my_var="Hello, World!"
export my_var

匯出變數後,可以在子殼層或子過程中存取其值。環境變數的優勢在於其能夠簡化流程。若沒有環境變數,每次執行程式或指令碼時,可能需要輸入完整的路徑。透過環境變數,Bash 知道要尋找特設定檔案或目錄的位置,因為這些路徑已儲存在如 PATH 等變數中。

此外,環境變數確保軟體在不同使用者環境中正確執行。例如,HOME 變數告訴應用程式使用者的家目錄位置,使程式可以在不需要每次明確指示的情況下,將檔案儲存在正確位置。

實務案例

假設你經常存取某個位於檔案系統深處的目錄。每次輸入完整路徑會相當麻煩。你可以建立一個自定義環境變數來儲存這個路徑:

export MY_DEEP_DIRECTORY="/this/is/a/very/long/path/that/I/use/often"

現在,只要輸入 cd $MY_DEEP_DIRECTORY ,Bash 就會立即帶你到那個目錄。

另一個常見的應用是修改 PATH 變數。PATH 變數告訴 Bash 要尋找可執行檔案的位置。如果你安裝了一個不在系統預設可執行路徑中的程式,可以將其位置加入到 PATH 中:

export PATH=$PATH:/path/to/my/program

這樣的加法允許你從任何終端機位置執行該程式,而不需要指定其完整路徑。

注意這裡的語法 $PATH: ,這樣做是將新路徑附加到現有路徑上。如果沒有這麼做,你會覆寫現有的 PATH ,導致錯誤直到你修復或重新啟動電腦。

內容解密:

  • my_var="Hello, World!": 定義一個名為 my_var 的變數並指定為 “Hello, World!"。
  • export my_var: 將 my_var 匯出為環境變數,使其在子過程中可用。
  • export MY_DEEP_DIRECTORY="/this/is/a/very/long/path/that/I/use/often": 建立一個名為 MY_DEEP_DIRECTORY 的環境變數來儲存一個深層目錄的路徑。
  • cd $MY_DEEP_DIRECTORY: 使用環境變數來切換目錄。
  • export PATH=$PATH:/path/to/my/program: 在現有路徑上附加新的可執行檔案路徑。

永久性環境變數

如果你希望某個環境變數在重新啟動後依然有效,可以將其放入 .bashrc 檔案中。要使 .bashrc 中的變更生效,請執行 source ~/.bashrc 指令。

指令碼範例

接下來是一個包含我們前面提到所有內容的指令碼範例:

#!/usr/bin/env bash
# 指令碼名稱
echo "這個指令碼的名稱是 $0."

# 將命令列引數指定給變數
name=$1
age=$2

# 使用前兩個引數
echo "第一個引數是 $1, 第二個引數是 $2."

# 使用者輸入的引數總數
echo "輸入的引數總共有 $# 個."

# 目前殼層的程式 ID
echo "目前殼層的程式 ID 是 $$."

# 命令列引數陣列
echo "命令列引數陣列: $@"

內容解密:

  • #!/usr/bin/env bash: 指定使用 Bash 作為指令碼的直譯器。
  • # 指令碼名稱: 指令碼中的註解。
  • $0: 構成指令碼名稱。
  • $1, $2: 命令列引數。
  • $#: 使用者輸入的引數總數。
  • $$: 目前殼層的程式 ID。
  • $@: 命令列引數陣列。

執行與許可權

這段指令碼可以透過兩種方式執行:

  1. 執行命令:bash ch03_variables_04.sh "first arg" 2nd 3rd fourth
  2. 轉換許可權並執行:先用 chmod +x ch03_variables_04.sh 轉換許可權,再執行 ./ch03_variables_04.sh 1 2 3 4

在第一種方式中,直接指定指令碼名稱和引數即可;而在第二種方式中則需先轉換指令碼許可權使其可執行。

條件判斷與分支

條件判斷陳述式是 Bash 指令碼中的基礎決策結構。最常見的是 if, else, 和 elif

if [ condition ]; then
    # 若條件成立則執行此處命令
else
    # 若條件不成立則執行此處命令
fi

例如:

num=10

if [ $num -gt 5 ]; then
    echo "num 大於5"
else
    echo "num 小於或等於5"
fi

此圖示說明瞭條件判斷陳述式流程:

  graph TD;
    A[開始] --> B{num > 5?};
    B -- 是 --> C[顯示 num 大於5];
    B --否 --> D[顯示 num 小於或等於5];
    C --> E[結束];
    D --> E[結束];

內容解密:

  • [ condition ]: 條件判斷陳述式。
  • -gt: 大於符號。
  • -lt: 小於符號。
  • -eq: 做為等於符號。

透過這些知識點及具體範例,玄貓希望能夠幫助你更深入理解 Bash 指令碼中的基本概念與應用。

條件判斷與資料處理

條件判斷基本觀念

在 Bash 指令碼中,條件判斷是一種常見且重要的技術。它能根據不同的狀況執行不同的程式碼區塊。基本的條件判斷以 if 陳述式為主,它會檢查特定的條件,如果條件成立,則執行相應的程式碼。以下是一個簡單的範例:

#!/usr/bin/env bash
USER="$1"
if [ "$USER" == 'steve' ]; then
  echo "Welcome back, Steve!"
fi

此範例中的指令碼會檢查第一個命令列引數是否為 steve,如果是,則輸出「Welcome back, Steve!」。這裡使用了方括號來包圍條件,並且用雙等號進行比較。

內容解密:

  • 程式碼解說
    • #!/usr/bin/env bash:這是 Bash 指令碼的標準開頭,指定要使用的 shell。
    • USER="$1":將第一個命令列引數指定給變數 USER
    • if [ "$USER" == 'steve' ]; then:開始 if 條件判斷,檢查變數 USER 是否等於 steve
    • echo "Welcome back, Steve!":如果條件成立,則輸出「Welcome back, Steve!」。
    • fi:結束 if 陳述式。

加入 else 分支

當我們想要在條件不成立時執行其他動作時,可以使用 else 分支。以下是一個範例:

#!/usr/bin/env bash
USER="$1"
if [ "$USER" == 'steve' ]; then
  echo "Welcome back, Steve!"
else
  echo "Access denied."
fi

在此範例中,如果變數 USER 不等於 steve,則輸出「Access denied.」。

內容解密:

  • 程式碼解說
    • 與上一個範例相同,但加入了 else 分支。
    • else:當條件不成立時執行的分支。
    • echo "Access denied.":如果條件不成立,則輸出「Access denied.」。

根據多重條件的分支

在某些情況下,我們需要檢查多個條件。這時可以使用 elif(else if)來實作。以下是範例:

#!/usr/bin/env bash
if [ "$USER" == 'steve' ]; then
  echo "Welcome back, Steve!"
elif [ "$USER" == 'admin' ]; then
  echo "Hello, admin."
else
  echo "Access denied."
fi

這段指令碼會依序檢查變數 $USER 是否等於 steveadmin,並輸出相應的訊息。

內容解密:

  • 程式碼解說
    • 與上一個範例相同,但加入了多個條件判斷。
    • elif [ "$USER" == 'admin' ]; then:檢查變數 $USER 是否等於 'admin'

深入理解 Bash 條件判斷

Bash 的條件判斷不僅限於簡單的比較操作。我們還可以檢查檔案屬性、變數值以及其他條件。以下是一些常見的檔案測試操作:

  • -e FILE:檢查檔案是否存在。
  • -f FILE:檢查檔案是否存在且為常規檔案。
  • -d FILE:檢查檔案是否存在且為目錄。
  • -r FILE:檢查檔案是否存在且可讀取。
  • -w FILE:檢查檔案是否存在且可寫入。
  • -x FILE:檢查檔案是否存在且可執行。

例如,我們可以先檢查一個檔案是否存在再進行操作:

#!/usr/bin/env bash
if [ -f "/path/to/file.txt" ]; then
  echo "File exists. Proceeding with read operation."
else
  echo "File does not exist. Aborting."
fi

這段指令碼會先檢查 /path/to/file.txt 是否存在且為常規檔案,如果存在則輸出「File exists. Proceeding with read operation.」,否則輸出「File does not exist. Aborting.」。

內容解密:

  • 程式碼解說
    • -f "/path/to/file.txt":檢查指定路徑的檔案是否存在且為常規檔案。

整數比較

在 Bash 中進行整數比較時,可以使用以下運算元:

  • -eq: 檢查兩個數值是否相等。
  • -ne: 檢查兩個數值是否不相等。
  • -gt: 檢查第一個數值是否大於第二個數值。
  • -ge: 檢查第一個數值是否大於或等於第二個數值。
  • -lt: 檢查第一個數值是否小於第二個數值。
  • -le: 檢查第一個數值是否小於或等於第二個數值。

例如:

#!/usr/bin/env bash
NUMBER=$1
if [ "$NUMBER" -gt 10 ]; then
  echo "The number is greater than 10."
else
  echo "The number is less than or equal to 10."
fi

此範例會檢查變數 $NUMBER 是否大於 10,根據結果輸出相應訊息。

內容解密:

  • 程式碼解說
    • [ "$NUMBER" -gt 10 ]: 檢查變數 $NUMBER 是否大於10。