Bash 的 extglob 擴展 glob 模式
在 Linux 的日常操作中,我們經常需要處理檔案與目錄的過濾。對於初學者而言,基本的 glob 模式(如 *.txt 或 ?)已經足夠應付大多數情境。然而,當需求變得複雜,例如「排除特定副檔名」或「匹配多個字首」時,單純的 glob 就會顯得力不從心。此時,Bash 內建的 extglob(Extended Globbing,擴展 glob 模式)便成了強大的利器。這篇文章將帶領大家深入了解如何開啟並運用 extglob,讓檔案處理變得更加靈活高效。
什麼是 extglob?
extglob 是 Bash 的一項擴充功能,它允許我們使用更強大的模式匹配語法。預設情況下,Bash 並未啟用此功能,因此在使用前必須先透過 shopt 指令將其開啟。
開啟方式非常簡單,只需執行:
shopt -s extglob
為了方便在腳本中重複使用,建議將此指令加入 ~/.bashrc 或 ~/.bash_profile 中。一旦啟用,我們就可以使用以下幾種核心的擴展模式:
!(pattern-list):匹配不符合 pattern-list 的任何內容。?(pattern-list):匹配零個或一個 pattern-list。*(pattern-list):匹配零個或多個 pattern-list。+(pattern-list):匹配一個或多個 pattern-list。@(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 模式的檔案」。
情境二:匹配多個特定字首
假設我們只想處理以 log 或 data 開頭的 .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.csv 和 data_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 處理。而正規表達式通常用於 grep、sed 等工具進行文本內容的匹配。兩者語法相似但應用場景不同。例如,extglob 無法直接用於 grep 的內容匹配,反之亦然。
小結
extglob 是 Bash 中一個被低估的強大功能。透過簡單的 shopt -s extglob 啟用後,我們可以使用 !, ?, *, +, @ 等符號進行複雜的檔案模式匹配。雖然在處理大量檔案時,find 指令依然更為可靠,但在日常互動式操作或簡單腳本中,extglob 能顯著提升工作效率,讓檔案過濾變得直觀且簡潔。掌握這項技巧,將使你的 Linux 操作更加得心應手。