六種方法打造出色的Shell腳本
1. 詳盡的錯誤處理和輸入驗證
清晰的錯誤信息對于良好的用戶體驗至關重要。這就是為什么在腳本中實現了詳盡的錯誤處理和輸入驗證。例如:
if [ -z "$1" ]
then
echo "Usage: evaluate.sh <fork name> (<fork name 2> ...)"
echo " for each fork, there must be a 'calculate_average_<fork name>.sh' script and an optional 'prepare_<fork name>.sh'."
exit 1
fi
這種方法可以幫助用戶快速識別和解決問題,從而節省時間并減少挫敗感。
2. 明了且色彩鮮明的輸出
為了讓腳本輸出更加清晰易讀,采用了ANSI顏色代碼來強調重要信息、警告和錯誤。比如:
BOLD_RED='\033[1;31m'
RESET='\033[0m'
echo -e "${BOLD_RED}ERROR${RESET}: ./calculate_average_$fork.sh does not exist." >&2
這種視覺上的區別可以幫助用戶快速掌握每條消息的本質。
3. 詳盡的進度報告
希望用戶能夠確切地了解腳本在每個步驟中正在做什么。為此,實現了一個函數,它在執行每個命令之前先打印該命令:
function print_and_execute() {
echo "+ $@" >&2
"$@"
}
這與內置的set -x
跟蹤輸出格式相匹配,但為腳本編寫者提供了更細致的控制,以決定打印哪些內容。
這種透明度不僅讓用戶保持知情,而且在出現問題時也有助于調試。
4. 策略性地使用 "set -e" 和 "set +e"
進行錯誤處理 希望確保如果腳本本身出現錯誤,腳本會立即退出,但如果個別分支遇到問題,也允許它繼續運行。為此,在腳本中策略性地使用了選項 "set -e" 和 "set +e"。以下是如何實現這種技術的:
# 在腳本開始處
set -eo pipefail
# 在為每個分支運行測試和基準測試之前
for fork in "$@"; do
set +e # 們不希望prepare.sh、test.sh或hyperfine在1個分支失敗時就退出腳本
# 運行準備腳本(簡化)
print_and_execute source "./prepare_$fork.sh"
# 運行測試套件(簡化)
print_and_execute $TIMEOUT ./test.sh $fork
# ...(其他特定于分支的操作)
done
set -e # 在特定于分支的操作后重新啟用錯誤退出
這種方法為腳本編寫者提供了細致的控制,以決定哪些錯誤會導致腳本退出,哪些可以用其他方式處理。
5. 平臺特定的適配
知道用戶可能會在不同的操作系統上運行此腳本,添加了邏輯來檢測操作系統并相應地調整腳本的行為:
if [ "$(uname -s)" == "Linux" ]; then
TIMEOUT="timeout -v $RUN_TIME_LIMIT"
else # 假設 MacOS
if [ -x "$(command -v gtimeout)" ]; then
TIMEOUT="gtimeout -v $RUN_TIME_LIMIT"
else
echo -e "${BOLD_YELLOW}WARNING${RESET} gtimeout not available, install with `brew install coreutils` or benchmark runs may take indefinitely long."
fi
fi
這確保了在不同環境中的一致體驗。許多#1BRC參與者在MacOS上開發,而評估機器運行linux。
6. 多次運行的帶時間戳的文件輸出
為了支持多次基準測試運行而不覆蓋先前的結果,實現了一個系統,用于帶時間戳的文件輸出。這允許用戶多次運行腳本并保留所有結果的歷史記錄。
filetimestamp=$(date +"%Y%m%d%H%M%S")
# ...(在每個分支的循環中)
HYPERFINE_OPTS="--warmup 0 --runs $RUNS --export-json $fork-$filetimestamp-timing.json --output ./$fork-$filetimestamp.out"
# ...(在基準測試之后)
echo "Raw results saved to file(s):"
for fork in "$@"; do
if [ -f "$fork-$filetimestamp-timing.json" ]; then
cat $fork-$filetimestamp-timing.json >> $fork-$filetimestamp.out
rm $fork-$filetimestamp-timing.json
fi
if [ -f "$fork-$filetimestamp.out" ]; then
echo " $fork-$filetimestamp.out"
fi
done
總結
本文[1]通過實施這些技術,目標是創建一個用戶友好、信息豐富且健壯的shell腳本,為用戶提供運行和分析基準測試的極佳體驗。希望這些想法能激發你提高你自己的shell腳本的用戶體驗!