Bash 5.1 功能與改進 是做什麼的?
Bash 5.1 於 2020 年 12 月發布,為現代 Shell 腳本引入了數項值得注意的功能與改進。
新的 Shell 變數
EPOCHSECONDS 和 EPOCHREALTIME
兩個用於存取當前時間的新特殊變數:
# 取得目前 Unix 時間戳記(秒)
echo "目前時間戳記:${EPOCHSECONDS}"
# 取得目前 Unix 時間戳記(微秒精度)
echo "高精度時間戳記:${EPOCHREALTIME}"
# 實用範例:簡單的基準測試
start="${EPOCHREALTIME}"
# ... 某些操作 ...
sleep 0.5
end="${EPOCHREALTIME}"
duration=$(awk "BEGIN {print ${end} - ${start}}")
echo "操作耗時 ${duration} 秒"
# 範例:使用精確時間戳記記錄日誌
log_message() {
printf '[%s.%06d] %s\n' \
"$(date -d "@${EPOCHSECONDS}" '+%Y-%m-%d %H:%M:%S')" \
"${EPOCHREALTIME#*.}" \
"$*"
}
log_message "開始處理"
使用案例:
- 精確的效能測量
- 用於日誌記錄的高解析度時間戳記
- 避免外部
date命令呼叫 - 腳本中的微秒級計時
SRANDOM 變數
加密強度的隨機數:
# 產生安全的隨機數(如果可用)
if [[ -n "${SRANDOM}" ]]; then
secure_random="${SRANDOM}"
echo "安全隨機數:${secure_random}"
else
echo "SRANDOM 不可用(需要 getrandom/getentropy)"
fi
# 實用範例:使用安全隨機數名稱產生暫存檔
temp_file="/tmp/secure_${SRANDOM}_${EPOCHSECONDS}.tmp"
注意: SRANDOM 需要系統支援 getrandom() 或 getentropy() 系統呼叫。
改進的重新導向語法
{varname} 重新導向
將檔案描述符指派給變數,以便更好地管理檔案控制代碼:
# 開啟檔案描述符並儲存到變數中
exec {fd}< input.txt
while IFS= read -r -u "${fd}" line; do
echo "讀取:${line}"
done
exec {fd}<&- # 關閉檔案描述符
# 實用範例:多個檔案控制代碼
exec {input_fd}< data.txt
exec {output_fd}> results.txt
exec {error_fd}> errors.txt
process_data() {
while IFS= read -r -u "${input_fd}" line; do
if validate_line "${line}"; then
echo "已處理:${line}" >&"${output_fd}"
else
echo "錯誤:${line}" >&"${error_fd}"
fi
done
}
process_data
exec {input_fd}<&-
exec {output_fd}>&-
exec {error_fd}>&-
優點:
- 使用命名檔案描述符取代魔術數字
- 自動 FD 分配可避免衝突
- 程式碼更具可讀性且更易於維護
- 更容易追蹤開啟的檔案控制代碼
陣列增強功能
改進的關聯式陣列處理
對複雜陣列操作的更好支援:
# 使用 typeset 宣告關聯式陣列
declare -A config=(
[host]="localhost"
[port]="8080"
[debug]="true"
)
# 增強的陣列展開
for key in "${!config[@]}"; do
printf '%s=%s\n' "${key}" "${config[${key}]}"
done
# 實用範例:設定解析器
parse_config() {
declare -gA app_config
local line key value
while IFS='=' read -r key value; do
[[ "${key}" =~ ^[[:space:]]*# ]] && continue # 跳過註解
[[ -z "${key}" ]] && continue # 跳過空行
# 去除空白字元
key="${key#"${key%%[![:space:]]*}"}"
key="${key%"${key##*[![:space:]]}"}"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
app_config["${key}"]="${value}"
done < config.ini
}
多維陣列支援
改進了巢狀陣列結構的處理。
Readline 8.1 整合
增強的文本編輯和命令列互動:
按鍵綁定與歷史記錄
# 在 ~/.inputrc 中配置 readline
# 啟用不區分大小寫的自動補全
set completion-ignore-case on
# 啟用可見的補全統計資訊
set visible-stats on
# 立即顯示所有補全項目
set show-all-if-ambiguous on
# 使用顏色顯示補全匹配
set colored-completion-prefix on
改進的歷史搜尋
# 在您的腳本或 .bashrc 中
# 將 Ctrl+R 綁定為反向增量搜尋(預設,但在 5.1 中增強)
bind '"\C-r": reverse-search-history'
# 將 Ctrl+S 綁定為正向增量搜尋
bind '"\C-s": forward-search-history'
# 改進的歷史記錄處理
shopt -s histappend # 附加到歷史記錄
shopt -s cmdhist # 多行命令視為單一項目
HISTCONTROL=ignoreboth # 忽略重複項和開頭空格
HISTSIZE=10000
HISTFILESIZE=20000
訊號處理改進
在子 Shell 和行程替代中更好地傳播訊號:
# 在子 Shell 中增強的 trap 處理
cleanup() {
echo "正在清理..." >&2
rm -f "${temp_file}"
exit 130 # 128 + SIGINT
}
trap cleanup SIGINT SIGTERM
temp_file=$(mktemp)
# 訊號正確透過管線傳播
long_running_task | process_output &
pid=$!
# 等待背景工作,並使用適當的訊號處理
wait "${pid}" 2>/dev/null
exit_code=$?
if [[ ${exit_code} -gt 128 ]]; then
signal=$((exit_code - 128))
echo "程序被訊號 ${signal} 終止" >&2
fi
錯誤修復與邊界案例
子 Shell 處理
在衍生子 Shell 時的行為改進:
# 更可靠的子 Shell 變數繼承
outer_var="parent"
(
# 子 Shell 現在更可靠地繼承父變數
echo "在子 Shell 中:${outer_var}"
inner_var="child"
)
# outer_var 仍然可存取,inner_var 則否
echo "在子 Shell 之後:${outer_var}"
模式匹配邊界案例
修正了 glob 模式匹配中的邊界案例:
# 更可靠的 glob 匹配,支援特殊字元
shopt -s nullglob # 無匹配的 glob 展開為空陣列
shopt -s extglob # 擴展模式匹配
# 範例:匹配檔案,並優雅處理無匹配情況
files=(*.txt)
if [[ ${#files[@]} -eq 0 ]]; then
echo "未找到 .txt 檔案"
else
printf '找到:%s\n' "${files[@]}"
fi
效能改進
- 迴圈中更快的變數展開
- 最佳化的陣列操作
- 大型陣列的記憶體用量減少
- 模式匹配的效率提升
相容性說明
從 Bash 5.0 升級
大多數腳本皆相容,但請注意:
EPOCHSECONDS和EPOCHREALTIME是新的 - 若目標為舊版本,請檢查變數是否存在SRANDOM可能無法在所有系統上使用- 部分展開行為的罕見邊界案例已修正
版本檢查
# 在使用 Bash 5.1 功能前檢查版本
if [[ "${BASH_VERSINFO[0]}" -ge 5 ]] && [[ "${BASH_VERSINFO[1]}" -ge 1 ]]; then
# 可以安全使用 Bash 5.1 功能
timestamp="${EPOCHSECONDS}"
else
# 針對舊版本的備援方案
timestamp=$(date +%s)
fi
參考資料
- Bash NEWS 檔案 - 官方發行說明
- GNU Bash 5.1 發行版 - 原始碼發行版
- Bash 手冊頁面:
man bash(關於版本特定功能的章節)
其他資源
如需更廣泛的 Bash 開發模式與最佳實務,請參閱:
- ../bash-development/SKILL.md - 核心 Bash 開發模式
- ../bash-portability/SKILL.md - 跨版本相容性