通过实施这些技术,目标是创建一个用户友好、信息丰富且功能强大的 shell 脚本,为运行和分析基准的用户提供出色的体验。我希望这些想法能激励您在自己的 shell 脚本中增强用户体验!
b1.全面的错误处理和输入验证/b
我认为清晰的错误消息对于良好的用户体验至关重要。这就是为什么我在整个脚本中实施了彻底的错误处理和输入验证。例如:
codeif -z "$1"
then
echo "Usage: evaluate.sh
echo " for each fork, there must be a 'calculate_average_
exit 1
fi/code
这种方法可以帮助用户快速识别和解决问题,从而节省他们的时间并减少挫折感。
b2. 清晰、色彩丰富的输出/b
为了使脚本的输出更具可读性和用户友好性,我使用了 ANSI 颜色代码来突出显示重要信息、警告和错误。例如:
codeBOLD_RED='\0331;31m'
RESET='\0330m'
echo -e "${BOLD_RED}ERROR${RESET}: ./calculate_average_$fork.sh does not exist." >&2/code
这种视觉区别有助于用户快速掌握每条消息的性质。
b3. 详细进度报告/b
我希望用户准确了解脚本在每个步骤中执行的操作。为了实现这一点,我实现了一个函数,在执行每个命令之前打印它:
codefunction print_and_execute() {
echo "+ $@" >&2
"$@"
}/code
这与 Bash 内置跟踪的输出格式相匹配set -x,但让脚本作者可以更精细地控制打印内容。
这种程度的透明度不仅可以让用户了解情况,而且在出现问题时还可以帮助调试。
b4. 使用“set -e”和“set +e”进行策略性错误处理/b
我希望确保脚本本身出现错误时立即退出,但同时允许它在个别分支遇到问题时继续运行。为了实现这一点,我在整个脚本中策略性地使用了 Bash 选项“set -e”和“set +e”。以下是我实施这项技术的方法:
codeAt 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/code
这种方法使脚本作者可以细粒度地控制哪些错误导致脚本退出以及哪些错误可以用其他方式处理。
b5. 针对特定平台的适配/b
知道用户可能会在不同的操作系统上运行该脚本,我添加了逻辑来检测操作系统并相应地调整脚本的行为:
codeif "$(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/code
这确保了在不同环境中获得一致的体验。例如,许多 #1BRC 参与者在 MacOS 上进行开发,而评估机器则运行 Linux。
b6. 多次运行的时间戳文件输出/b
为了支持多次基准测试运行而不覆盖之前的结果,我实现了一个带时间戳的文件输出系统。这允许用户多次运行脚本并保留所有结果的历史记录。以下是我的做法:
codefiletimestamp=$(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
--/code
查看#1BRC repo 中的完整基准评估脚本:url=https://github.com/gunnarmorling/1brc/blob/main/evaluate.shevaluate.sh/url
list
*在 Hacker News 上:url=https://news.ycombinator.com/item?id=41512899在 Hacker News 上讨论此帖子/url
/list