shell脚本创建出色用户体验的6种技巧
# 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
1
2
3
4
5
6
2
3
4
5
6
这种方法可以帮助用户快速识别和解决问题,从而节省他们的时间并减少挫折感。
# 2.输出清晰、色彩丰富
为了使脚本的输出更具可读性和用户友好性,我使用了 ANSI 颜色代码来突出显示重要信息、警告和错误。例如:
BOLD_RED='\033[1;31m'
RESET='\033[0m'
echo -e "${BOLD_RED}ERROR${RESET}: ./calculate_average_$fork.sh does not exist." >&2
1
2
3
2
3
这种视觉区别有助于用户快速掌握每条消息的性质。
# 3.详细进度报告
我希望用户能够准确了解脚本在每个步骤中执行的操作。为了实现这一点,我实现了一个函数,在执行每个命令之前打印它:
function print_and_execute() {
echo "+ $@" >&2
"$@"
}
1
2
3
4
2
3
4
这与 Bash 内置跟踪的输出格式相匹配set -x
,但让脚本作者可以更精细地控制打印内容。
这种程度的透明度不仅可以让用户了解情况,而且在出现问题时还可以帮助调试。
# 4. 使用“set -e”和“set +e”进行策略性错误处理
我希望确保脚本本身出现错误时立即退出,但同时允许它在个别分支遇到问题时继续运行。为了实现这一点,我在整个脚本中策略性地使用了 Bash 选项“set -e”和“set +e”。以下是我实施这项技术的方法:
# At the beginning of the script
set -eo pipefail
# Before running tests and benchmarks for each fork
for fork in "$@"; do
set +e # we don't want prepare.sh, test.sh or hyperfine failing on 1 fork to exit the script early
# Run prepare script (simplified)
print_and_execute source "./prepare_$fork.sh"
# Run the test suite (simplified)
print_and_execute $TIMEOUT ./test.sh $fork
# ... (other fork-specific operations)
done
set -e # Re-enable exit on error after the fork-specific operations
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
这种方法使脚本作者可以细粒度地控制哪些错误导致脚本退出以及哪些错误可以用其他方式处理
# 5. 针对特定平台的适配
知道用户可能会在不同的操作系统上运行该脚本,我添加了逻辑来检测操作系统并相应地调整脚本的行为:
if [ "$(uname -s)" == "Linux" ]; then
TIMEOUT="timeout -v $RUN_TIME_LIMIT"
else # Assume 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
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
这确保了在不同环境中获得一致的体验。例如,许多 #1BRC 参与者在 MacOS 上进行开发,而评估机器则运行 Linux
# 6. 多次运行的时间戳文件输出
为了支持多次基准测试运行而不覆盖之前的结果,我实现了一个带时间戳的文件输出系统。这允许用户多次运行脚本并保留所有结果的历史记录。以下是我的做法:
filetimestamp=$(date +"%Y%m%d%H%M%S")
# ... (in the loop for each fork)
HYPERFINE_OPTS="--warmup 0 --runs $RUNS --export-json $fork-$filetimestamp-timing.json --output ./$fork-$filetimestamp.out"
# ... (after the benchmarks)
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
完整脚本:https://github.com/gunnarmorling/1brc/blob/main/evaluate.sh
上次更新: 2025/01/09, 21:27:48
← mysql备份企业示例 指针→