基于Shell/bash实现测试名与run-ksql-test结果的逐行映射
问题:Shell脚本实现测试名与测试结果的对应映射
前提
使用run-ksql-test工具,其输出格式见下文命令输出部分。现有测试文件,需将测试状态与测试名对应映射,且受DevOps限制只能使用Shell/bash实现。
测试文件格式
--@test: test Name 1 <multiple sql statements> --@test: testName2 <multiple sql statements> --@test: test Name3 <multiple sql statements>
命令输出
若干无特定格式且不含">>>"的行 [<timestamp>]: >>> Test Passed 若干无特定格式且不含">>>"的行 [<timestamp>]: >>> Test Passed 若干无特定格式且不含">>>"的行 [<timestamp>]: >>> Test Failed 若干无特定格式且不含">>>"的行
期望结果
--@test: test Name 1 [<timestamp>]: >>> Test Passed --@test: testName2 [<timestamp>]: >>> Test Passed --@test: test Name3 [<timestamp>]: >>> Test Failed
需保留两边的完整行内容。
约束
- 仅使用Shell代码,优先使用Linux/Unix默认工具(awk、grep、tr、cut、cat、sed等)。
现有问题
尝试的脚本会将带空格的测试名按单词拆分,无法得到期望格式,且未正确提取完整的测试结果行。现有代码片段如下:
do echo "---------------- TESTING $test_file ----------------" run-ksql-test --test-directory $test_file --temp-folder $TEMP_FOLDER > $LOG_DIR/$(basename $test_file) #take Names Of the tests from assembled query file test_names=($(cat $test_file | grep -Eo '\-\-\@.*')) #also tried similar variations but outupt is either one chunk or broken into words #take results from the logs for that file test_results=($(cat $LOG_DIR/$(basename $test_file) | grep -Eoi '>>>+(Passed|Failed)')) for ((i=0; i<${#test_names[@]}; i++)); do echo "${test_names[i]} ${test_results[i]}" done sleep 3 done
解决方案
方法1:使用awk关联处理(推荐)
用awk一次性处理测试文件和日志文件,将测试名存入数组,读取日志中的结果行后按顺序对应输出,无需处理Shell数组的空格拆分问题:
do echo "---------------- TESTING $test_file ----------------" run-ksql-test --test-directory "$test_file" --temp-folder "$TEMP_FOLDER" > "$LOG_DIR/$(basename "$test_file")" log_file="$LOG_DIR/$(basename "$test_file")" awk ' BEGIN { idx=0; res_idx=0; } # 从测试文件提取完整测试名行 FILENAME == ARGV[1] { if ($0 ~ /^--@test:/) { tests[++idx] = $0; } next; } # 从日志文件提取完整结果行 FILENAME == ARGV[2] { if ($0 ~ /\[.*\]: >>> Test (Passed|Failed)/) { res[++res_idx] = $0; } } # 遍历输出对应关系 END { for (i=1; i<=idx; i++) { printf "%-30s %s\n", tests[i], res[i]; } } ' "$test_file" "$log_file" sleep 3 done
方法2:修复Shell数组读取逻辑
如果坚持用Shell数组,需修改IFS(内部字段分隔符)为换行,确保按整行读取测试名和结果,避免空格拆分:
do echo "---------------- TESTING $test_file ----------------" run-ksql-test --test-directory "$test_file" --temp-folder "$TEMP_FOLDER" > "$LOG_DIR/$(basename "$test_file")" log_file="$LOG_DIR/$(basename "$test_file")" # 按行读取测试名,禁用空格拆分 IFS=$'\n' read -r -d '' -a test_names < <(grep -E '^--@test:' "$test_file") # 按行读取完整测试结果行 IFS=$'\n' read -r -d '' -a test_results < <(grep -E '\[.*\]: >>> Test (Passed|Failed)' "$log_file") # 对应输出 for ((i=0; i<${#test_names[@]}; i++)); do echo "${test_names[i]} ${test_results[i]}" done sleep 3 done
关键说明
- 所有文件路径用双引号包裹,避免文件名含空格时出错。
- 方法1的awk实现更稳定,适合复杂文本处理场景;方法2直接修复原脚本的数组读取问题,逻辑更直观。
内容的提问来源于stack exchange,提问作者deepakmeena
相关产品推荐
相关产品推荐

