Bash 的 extglob 擴展 glob 模式 文章首圖

Bash 的 extglob 擴展 glob 模式

Bash 的 extglob 擴展 glob 模式

在 Linux 的日常操作中,我們經常需要處理檔案與目錄的過濾。對於初學者而言,基本的 glob 模式(如 *.txt?)已經足夠應付大多數情境。然而,當需求變得複雜,例如「排除特定副檔名」或「匹配多個字首」時,單純的 glob 就會顯得力不從心。此時,Bash 內建的 extglob(Extended Globbing,擴展 glob 模式)便成了強大的利器。這篇文章將帶領大家深入了解如何開啟並運用 extglob,讓檔案處理變得更加靈活高效。

什麼是 extglob?

extglob 是 Bash 的一項擴充功能,它允許我們使用更強大的模式匹配語法。預設情況下,Bash 並未啟用此功能,因此在使用前必須先透過 shopt 指令將其開啟。

開啟方式非常簡單,只需執行:

shopt -s extglob

為了方便在腳本中重複使用,建議將此指令加入 ~/.bashrc~/.bash_profile 中。一旦啟用,我們就可以使用以下幾種核心的擴展模式:

  1. !(pattern-list):匹配符合 pattern-list 的任何內容。
  2. ?(pattern-list):匹配零個或一個 pattern-list。
  3. *(pattern-list):匹配零個或多個 pattern-list。
  4. +(pattern-list):匹配一個或多個 pattern-list。
  5. @(pattern-list):匹配恰好一個 pattern-list。

這些模式中的 pattern-list 可以是由 | 分隔的多個模式,例如 *.jpg|*.png

實戰應用:檔案過濾與刪除

讓我們透過幾個實際的場景來演示 extglob 的威力。假設我們有一個包含多種檔案類型的資料夾,我們想要進行特定的過濾操作。

情境一:排除特定副檔名

假設我們想刪除目前目錄下所有副檔名不是 .txt 的檔案,但保留 .txt 檔案。使用傳統 glob,我們很難直接做到「排除」,但使用 extglob 就輕而易舉了。

首先,建立一些測試檔案:

# 建立測試環境
mkdir -p extglob_test
cd extglob_test
touch file1.txt file2.txt file3.log file4.csv file5.txt
ls -l

現在,我們使用 !(...) 模式來匹配所有非 .txt 的檔案,並將其刪除:

# 啟用 extglob
shopt -s extglob

# 刪除所有非 .txt 的檔案
rm -v !(file*.txt)

執行後,你會發現只有 file1.txt, file2.txt, file5.txt 被保留,其他檔案都被刪除了。這裡的 !(file*.txt) 意思是「匹配任何不符合 file*.txt 模式的檔案」。

情境二:匹配多個特定字首

假設我們只想處理以 logdata 開頭的 .csv 檔案。傳統 glob 無法直接表達「或」的邏輯,但 extglob 可以。

# 建立更多測試檔案
touch log_report.csv data_backup.csv other_file.csv
ls -l

使用 @(pattern-list) 來匹配恰好一個符合條件的字首:

# 列出所有以 log 或 data 開頭且副檔名為 csv 的檔案
ls -l @(log|data)*.csv

輸出結果將僅顯示 log_report.csvdata_backup.csv,而 other_file.csv 會被忽略。這種語法在處理具有多種命名規範的檔案時非常有用。

情境三:複雜的檔案清理腳本

讓我們將這些知識整合成一個完整的腳本範例。這個腳本會清理目前目錄,保留 .txt.md 檔案,並刪除其他所有檔案。

#!/bin/bash

# 確保 extglob 已啟用
shopt -s extglob

# 定義要保留的副檔名
KEEP_PATTERNS="*.txt|*.md"

# 顯示即將被刪除的檔案清單
echo "準備刪除以下檔案:"
ls -1 !(file*.txt|file*.md) 2>/dev/null

# 詢問使用者確認
read -p "確定要刪除嗎?(y/n): " confirm

if [[ "$confirm" == "y" ]]; then
    # 執行刪除
    # 注意:!(...) 會匹配所有不屬於 *.txt 或 *.md 的檔案
    rm -v !(file*.txt|file*.md)
    echo "清理完成!"
else
    echo "操作已取消。"
fi

請注意,在 rm 指令中使用 !(...) 時,如果目錄中沒有符合排除條件的檔案,Bash 可能會報錯。因此,在實際生產環境中,建議加上 2>/dev/null 來隱藏錯誤訊息,或使用 find 指令作為更安全的替代方案。

常見問題

1. 為什麼我的 extglob 模式無效?

最常見的原因是 extglob 功能未啟用。Bash 預設關閉此功能,因此必須手動執行 shopt -s extglob。你可以透過 shopt | grep extglob 來檢查當前狀態。如果輸出為 extglob on,則表示已啟用。

2. extglob 與正規表達式(Regex)有何不同?

extglob 是檔案名稱的模式匹配(globbing),主要用於 shell 展開(expansion),在命令執行前由 shell 處理。而正規表達式通常用於 grepsed 等工具進行文本內容的匹配。兩者語法相似但應用場景不同。例如,extglob 無法直接用於 grep 的內容匹配,反之亦然。

小結

extglob 是 Bash 中一個被低估的強大功能。透過簡單的 shopt -s extglob 啟用後,我們可以使用 !, ?, *, +, @ 等符號進行複雜的檔案模式匹配。雖然在處理大量檔案時,find 指令依然更為可靠,但在日常互動式操作或簡單腳本中,extglob 能顯著提升工作效率,讓檔案過濾變得直觀且簡潔。掌握這項技巧,將使你的 Linux 操作更加得心應手。