Hero Image
進階 Shell 腳本技巧:用 Bash 自動化複雜任務

進階 Shell 腳本技巧:用 Bash 自動化複雜任務 使用內建指令 內建指令執行更快,因為不需要載入外部程序。 減少子殼層 子殼層會帶來效能成本。 # Inefficient output=$(cat file.txt) # Efficient output=$(<file.txt) 使用陣列處理大量資料 處理大量資料時,陣列比多個變數更有效率,也更好管理。 # Inefficient item1="apple" item2="banana" item3="cherry" # Efficient items=("apple" "banana" "cherry") for item in "${items[@]}"; do echo "$item" done 啟用 Noclobber 避免檔案被意外覆寫。 set -o noclobber 使用函式 函式可以封裝並重用程式碼,讓腳本更乾淨、重複更少。 高效的檔案操作 進行檔案操作時,使用更有效率的技巧以降低資源消耗。 # Inefficient while read -r line; do echo "$line" done < file.txt # Efficient while IFS= read -r line; do echo "$line" done < file.txt 平行處理 像 xargs 和 GNU parallel 這類工具非常實用。 錯誤處理 健全的錯誤處理對建立可靠、易維護的腳本至關重要。 # Exit on Error: Using set -e ensures that your script exits immediately if any command fails, preventing cascading errors. set -e # Custom Error Messages: Implement custom error messages to provide more context when something goes wrong. command1 || { echo "command1 failed"; exit 1; } # Trap Signals: Use the `trap` command to catch and handle signals and errors gracefully. trap 'echo "Error occurred"; cleanup; exit 1' ERR function cleanup() { # Cleanup code } # Validate Inputs: Always validate user inputs and script arguments to prevent unexpected behavior. if [[ -z "$1" ]]; then echo "Usage: $0 <argument>" exit 1 fi # Logging: Implement logging to keep track of script execution and diagnose issues. logfile="script.log" exec > >(tee -i $logfile) exec 2>&1 echo "Script started" 自動化複雜的系統管理工作 自動化備份 系統監控 使用者管理 自動更新 網路設定

Hero Image
寫 Web 也可以用 Makefile:好好管理你的環境流程

寫 Web 也可以用 Makefile:好好管理你的環境流程 How I stopped worrying and loved Makefiles 注意:Makefile 的縮排應使用 Tab,否則會出現語法問題。 Makefile 的主要本體:Target up: cp .env.example .env docker compose up -d workspace stop: docker compose stop zsh: docker compose exec workspace zsh 本例有三個 Target:up、stop、zsh。Makefile 預設將第一個 Target 視為 Goal(不能是點(dot)開頭的 Target),是專案的最主要流程,可以直接用 make 執行。以本例來說,執行 make 和 make up 是一樣的結果。 但其實剛剛複製檔案的例子不是常見的 Make 用法。Make 的強項是在自動判斷有沒有必要執行每個 Target 的流程。例如我們常常將機敏資料放在 .env 中,若 .env 已經存在,就不應該再複製 .env.example 覆寫過去了。這時候我們可以把 .env 做成一個 Target: up: .env docker compose up -d workspace .env: cp .env.example .env Target 名稱預設是被視為檔名的。Make 之所以稱為 make,就是想要「製作」出指定的 Target,當符合指定條件時(如檔案不存在)才會執行 Target 的內容。 以本例來說,我們執行 up Target 時,如果 .env 不存在,就會先執行 .env Target 以複製出 .env,接著才會啟動 workspace container。如果執行 up Target 時 .env 已經存在,就會略過 .env Target,直接啟動 workspace container。 同樣地,如果我們目錄中有「up」這個檔案, up Target 就不會被執行了。這時我們可以設定 Phony Target,告訴 Make 哪些 Target 不是檔案的名稱,而是單純流程的命名。寫法如下: .PHONY: up stop zsh 來點變數 Make 當然也支援變數(Variable),與常見的 Unix 環境變數慣例相同,我們習慣用 SCREAMING_SNAKE_CASE 表示法(全大寫和底線的表示法)。並且在使用時以 $() 包裹變數名稱。

Hero Image
在 Bash 中解析命令列參數

在 Bash 中解析命令列參數 getopts getopts optstring opt [arg ...] #!/bin/bash while getopts 'abc:h' opt; do case "$opt" in a) echo "Processing option 'a'" ;; b) echo "Processing option 'b'" ;; c) arg="$OPTARG" echo "Processing option 'c' with '${OPTARG}' argument" ;; ?|h) echo "Usage: $(basename $0) [-a] [-b] [-c arg]" exit 1 ;; esac done shift "$(( $OPTIND -1 ))" optstring 代表支援的選項。若某個選項需要參數,則在它後面加冒號 (:)。例如選項 c 需要參數,會寫成 c: 當選項有關聯參數時,getopts 會將參數字串存到 OPTARG shell 變數中。例如 option c 的參數會存到 OPTARG。 opt 包含已解析的選項。 #!/bin/bash while getopts ':abc:h' opt; do case "$opt" in a) echo "Processing option 'a'" ;; b) echo "Processing option 'b'" ;; c) arg="$OPTARG" echo "Processing option 'c' with '${OPTARG}' argument" ;; h) echo "Usage: $(basename $0) [-a] [-b] [-c arg]" exit 0 ;; :) echo -e "option requires an argument.\nUsage: $(basename $0) [-a] [-b] [-c arg]" exit 1 ;; ?) echo -e "Invalid command option.\nUsage: $(basename $0) [-a] [-b] [-c arg]" exit 1 ;; esac done shift "$(( $OPTIND -1 ))" 注意我們也更新了 optstring,現在以冒號 (:) 開頭,會抑制預設的錯誤訊息。 當 OPTERR 變數設為 0 時,getopts 會停用錯誤訊息輸出。 使用 getopt 解析長選項 #!/bin/bash VALID_ARGS=$(getopt -o abg:d: --long alpha,beta,gamma:,delta: -- "$@") if [[ $? -ne 0 ]]; then exit 1; fi eval set -- "$VALID_ARGS" while [ : ]; do case "$1" in -a | --alpha) echo "Processing 'alpha' option" shift ;; -b | --beta) echo "Processing 'beta' option" shift ;; -g | --gamma) echo "Processing 'gamma' option. Input argument is '$2'" shift 2 ;; -d | --delta) echo "Processing 'delta' option. Input argument is '$2'" shift 2 ;; --) shift; break ;; esac done -o 選項代表短選項 --long 選項代表長選項