我有自己的 Redis 服务器实现,我想通过 shell 脚本对其进行测试。
一般的想法是通过 向它提供一些命令nc
,并且由于nc
将我的程序的输出(响应)打印到stdout
,因此在脚本变量中捕获响应并将其与预期输出进行比较。
我无法让它工作,我不知道问题是什么以及如何解决它。
这是脚本的一部分:
#!/bin/bash
set -eu
PORT=6380;
RUST_LOG=info ./run.sh --port $PORT 2>/dev/null & sleep 1; # Give it some time to start.
i=0;
i=$((i+1)); printf 'Running test #%d...' "$i";
response=$(printf "*1\r\n\$4\r\nPING\r\n" | nc localhost $PORT);
if [ "$response" = '+PONG\r\n' ]; then
printf ' PASSED'
else
printf ' FAILED\nGot:\n%s\n\n' "$response"
fi;
sleep 0.1;
pkill redis-server;
这只是测试的一个示例。当用户发送PING
命令时,预期的响应是PONG
,但它被编码并发送回+PONG\r\n
。
本次测试运行的 CLI 输出($ ./test.sh
)为:
Running test #1... FAILED
Got:
+PONG
因此,看起来该变量$response
确实包含了它应该包含的内容。
我尝试从参考输出中删除、、,但没有成功,只是想看看是否有+
帮助\r
。\n
\r\n
我将在响应中进行更复杂的测试,其中包括需要转义的字符($
),例如。\$5\r\nHello
顺便说一句,手动设置response
可以按预期工作。
response='+PONG\r\n';
if [ "$response" = '+PONG\r\n' ]; then
echo Equal
else
echo Different
fi;
正如预期的那样,这将打印Equal
。
通过 添加调试输出后set -ex
,我可以看到$response
存储+PONG\r
,即没有\n
。
Running test #1...++ printf '*1\r\n$4\r\nPING\r\n'
++ nc localhost 6380
+ response=$'+PONG\r'
+ '[' $'+PONG\r' = '+PONG\r\n' ']'
+ printf ' FAILED\nGot:\n%s\n\n' $'+PONG\r'
FAILED
Got:
+PONG
好的,那么设置参考输出+PONG\r
应该可以工作,对吗?
Running test #1...++ printf '*1\r\n$4\r\nPING\r\n'
++ nc localhost 6380
+ response=$'+PONG\r'
+ '[' $'+PONG\r' = '+PONG\r' ']'
+ printf ' FAILED\nGot:\n%s\n\n' $'+PONG\r'
FAILED
Got:
+PONG
显然不是。
我尝试像这样包装:response
,但没有成功。{}
if [ "${response}" = '+PONG\r' ]; then
我错过了什么?
我也很好奇想知道是怎么迷路的以及为什么\n
迷路。
zsh
如果需要注意的话,我是在 Mac 上运行它的,但是系统明确告诉它使用bash
。
如果我ps -p $$
从测试脚本执行,我会得到51547 ttys003 0:00.02 /bin/bash ./test.sh
。
您的比较测试未按预期进行,原因有二:
服务器的实际响应(根据我从您的原始帖子和评论中理解)是字符串
+PONG
后跟一个回车符(又称 CR、^M、\r),再跟一个换行符(又称换行符、LF、NL、^J、\n)。但是,您的测试尝试将其与文字字符进行比较\r\n
。换句话说,您尝试将字符与其反斜杠转义的等效字符进行比较。response
由于命令替换行为,变量中捕获的尾随换行符被删除。要修复您的测试,您可以:
确保比较的字符正确。换句话说,采用 @markp-fuso 的语法作为
$'+PONG\r\n'
参考值。确保换行符没有被删除。一种解决方案是在所需值的末尾附加一个一次性值,然后在命令替换完成后将其删除。为了保留退出状态,还需要一些额外的技巧。此处有详细说明。
综合起来,这里有一个示例解决方案(没有退出代码技巧):
请注意,该
$'...'
语法最初来自 ksh93,虽然现在自sh
POSIX 规范的 2024 版以来一直是标准,但仍然不受一些sh
实现的支持,特别是dash
Debiansh
和衍生产品的,因此如果您希望脚本可移植到其他系统,则可能需要将您的 shebang 更改为#! /usr/bin/env zsh
或#! /usr/bin/env bash
(在仍然是 ksh88 或 pdksh 的ksh
系统上不起作用)。ksh
另请注意,如果使用强引号 ( ) 代替 ,则无需对
$
with进行转义,因为其中仍会执行参数扩展。您也可以使用( ,其中也没有参数扩展) ,在这种情况下,会在传递给 之前由该运算符转换为 CR 和 LF 控制字符,而不是自行转换它们。\
'...'
"..."
$'...'
\r
\n
$'...'
printf
printf
使用
printf '%s\r\n' '*1' '$4' PING
还可以更清楚地表明您想要输出三个 CRLF 分隔的行。