如何使用Bats测试含read -p的anykey与yesno脚本函数?
测试Shell脚本中的输入提示函数:anykey和yesno
我来帮你解决这两个测试问题,咱们一个个拆解:
问题1:为什么提示文本没出现在$output中?怎么捕获它?
你遇到的核心问题是:read命令的-p参数是把提示信息输出到标准错误(stderr),而非标准输出(stdout)。通常我们捕获脚本输出时默认只抓取stdout,所以看不到这些提示文本。
要捕获提示信息,测试时需要把stderr合并到stdout中,用2>&1重定向即可:
# 假设你的工具脚本叫utils.sh source utils.sh # 捕获anykey的提示文本(anykey本身无stdout输出,提示仅在stderr) output=$(anykey "Press to proceed..." 2>&1) echo "$output" # 现在就能看到提示内容了
问题2:如何在测试中强制跳出yesno的while循环?
yesno的循环会一直运行,直到输入Y或N(你的代码里case分支匹配这两个字符时会break)。测试时我们可以通过模拟输入直接传入Y/N,触发退出逻辑。
方法1:用Here-String直接传入输入
这是最简便的bash原生方法,无需额外工具:
source utils.sh # 模拟输入Y,让yesno收到后跳出循环 output=$(yesno "Confirm? " <<< "Y" 2>&1) echo "$output" # 你会看到提示文本"Confirm? ",且函数正常退出
测试N的情况只需把<<< "Y"换成<<< "N"即可。
方法2:用管道输入
另一种直观方式是用echo管道传递输入:
echo "N" | yesno "Are you sure? " 2>&1
方法3:用expect脚本(复杂交互场景)
如果测试需要等待提示出现再输入的逻辑,可以用expect工具实现更灵活的交互:
#!/usr/bin/expect spawn bash -c "source ./utils.sh && yesno 'Yes or no?'" expect "Yes or no? " send "Y\r" expect eof
这个脚本会等待提示出现后发送Y,让函数退出循环。
完整测试示例
假设你的工具脚本utils.sh内容为:
function anykey() { read -n 1 -r -s -p "${1:-Press any key to continue ...}" } function yesno() { local -u yn while true; do # shellcheck disable=SC2162 read -N1 -p "${1:-Yes or no?} " yn case $yn in Y | N) echo "You chose $yn" break ;; *) echo "Please enter Y or N" ;; esac done }
对应的测试脚本test_utils.sh可以这么写:
#!/bin/bash source ./utils.sh echo "=== Testing anykey ===" # 捕获提示文本 anykey_prompt=$(anykey "Custom prompt: " 2>&1) echo "Captured prompt: '$anykey_prompt'" echo -e "\n=== Testing yesno with Y ===" yesno_output=$(yesno "Confirm action? " <<< "Y" 2>&1) echo "$yesno_output" echo -e "\n=== Testing yesno with invalid input then N ===" # 模拟先输入无效字符,再输入N yesno_output=$(printf "X\nN\n" | yesno "Retry? " 2>&1) echo "$yesno_output"
运行这个测试脚本,就能看到所有提示文本和函数输出了。
内容的提问来源于stack exchange,提问作者harleypig
相关产品推荐
相关产品推荐

