diff --git a/Snipaste_2026-04-25_18-30-51.jpg b/Snipaste_2026-04-25_18-30-51.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cd08b66f701d564efc83ad06978864de3fbf0815 Binary files /dev/null and b/Snipaste_2026-04-25_18-30-51.jpg differ diff --git a/bash-arithmetic-operations.sh b/bash-arithmetic-operations.sh new file mode 100644 index 0000000000000000000000000000000000000000..41431906f60c751dc5c391b3e64ebc74dfab4d2d --- /dev/null +++ b/bash-arithmetic-operations.sh @@ -0,0 +1,108 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-003-bash-arithmetic-operations +# @用例名称: bash-arithmetic-operations +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash 算术运算功能,包括 $(()) 算术展开、let 命令、(()) 复合命令、位运算以及比较运算等 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包 + assert_true yum install -y bash + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: 使用 $(()) 进行加法运算 + # @预期结果: 加法结果正确 + result=$((10 + 5)) + assert_true [ "$result" -eq 15 ] + + # @测试步骤: 使用 $(()) 进行减法运算 + # @预期结果: 减法结果正确 + result=$((20 - 8)) + assert_true [ "$result" -eq 12 ] + + # @测试步骤: 使用 $(()) 进行乘法运算 + # @预期结果: 乘法结果正确 + result=$((6 * 7)) + assert_true [ "$result" -eq 42 ] + + # @测试步骤: 使用 $(()) 进行除法运算 + # @预期结果: 整除结果正确 + result=$((15 / 4)) + assert_true [ "$result" -eq 3 ] + + # @测试步骤: 使用 $(()) 进行取模运算 + # @预期结果: 取模结果正确 + result=$((17 % 5)) + assert_true [ "$result" -eq 2 ] + + # @测试步骤: 使用 $(()) 进行幂运算 + # @预期结果: 幂运算结果正确 + result=$((2 ** 8)) + assert_true [ "$result" -eq 256 ] + + # @测试步骤: 使用 let 命令进行算术运算 + # @预期结果: let 命令运算结果正确 + let "val = 3 * 4 + 2" + assert_true [ "$val" -eq 14 ] + + # @测试步骤: 使用 (()) 复合命令作为条件判断 + # @预期结果: 条件为真时返回 0 + (( 5 > 3 )) + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 (()) 复合命令进行自增操作 + # @预期结果: 自增结果正确 + counter=10 + (( counter++ )) + assert_true [ "$counter" -eq 11 ] + + # @测试步骤: 使用位与运算 + # @预期结果: 位运算结果正确 + result=$(( 12 & 10 )) + assert_true [ "$result" -eq 8 ] + + # @测试步骤: 使用位或运算 + # @预期结果: 位或运算结果正确 + result=$(( 12 | 3 )) + assert_true [ "$result" -eq 15 ] + + # @测试步骤: 使用左移运算 + # @预期结果: 左移结果正确 + result=$(( 1 << 4 )) + assert_true [ "$result" -eq 16 ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +############################################################################### diff --git a/bash-array-operations.sh b/bash-array-operations.sh new file mode 100644 index 0000000000000000000000000000000000000000..a5155b8cf9e1d166eaa731595a707267055a047d --- /dev/null +++ b/bash-array-operations.sh @@ -0,0 +1,107 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-004-bash-array-operations +# @用例名称: bash-array-operations +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash 数组功能,包括数组声明、元素赋值访问、数组长度、数组切片、遍历、删除元素以及关联数组操作 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包 + assert_true yum install -y bash + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: 声明并初始化索引数组 + # @预期结果: 数组元素可以正确访问 + arr=(apple banana cherry) + assert_true [ "${arr[0]}" = "apple" ] + assert_true [ "${arr[1]}" = "banana" ] + assert_true [ "${arr[2]}" = "cherry" ] + + # @测试步骤: 获取数组长度 + # @预期结果: 返回正确的元素个数 + arr=(one two three four five) + len="${#arr[@]}" + assert_true [ "$len" -eq 5 ] + + # @测试步骤: 修改数组元素 + # @预期结果: 元素被正确修改 + arr[1]="modified" + assert_true [ "${arr[1]}" = "modified" ] + + # @测试步骤: 获取所有数组元素 + # @预期结果: 所有元素正确展开 + arr=(x y z) + all="${arr[@]}" + echo "$all" | grep -q "x" + assert_true [ $? -eq 0 ] + echo "$all" | grep -q "z" + assert_true [ $? -eq 0 ] + + # @测试步骤: 数组切片操作 + # @预期结果: 切片返回正确的子数组 + arr=(a b c d e) + slice=("${arr[@]:1:3}") + assert_true [ "${slice[0]}" = "b" ] + assert_true [ "${slice[2]}" = "d" ] + + # @测试步骤: 追加元素到数组 + # @预期结果: 元素成功追加,长度增加 + arr=(1 2 3) + arr+=(4 5) + assert_true [ "${#arr[@]}" -eq 5 ] + assert_true [ "${arr[4]}" = "5" ] + + # @测试步骤: 使用 unset 删除数组元素 + # @预期结果: 元素被删除 + arr=(p q r) + unset 'arr[1]' + assert_true [ -z "${arr[1]}" ] + + # @测试步骤: 关联数组(declare -A)赋值与访问 + # @预期结果: 键值对可以正确存取 + declare -A assoc + assoc["key1"]="value1" + assoc["key2"]="value2" + assert_true [ "${assoc[key1]}" = "value1" ] + assert_true [ "${assoc[key2]}" = "value2" ] + + # @测试步骤: 获取关联数组所有键 + # @预期结果: 所有键可以正确枚举 + keys=("${!assoc[@]}") + assert_true [ "${#keys[@]}" -eq 2 ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +############################################################################### diff --git a/bash-builtin-commands.sh b/bash-builtin-commands.sh new file mode 100644 index 0000000000000000000000000000000000000000..52b6cf31baddd2e758b1a81d9c22b7b97b1becb8 --- /dev/null +++ b/bash-builtin-commands.sh @@ -0,0 +1,115 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-011-bash-builtin-commands +# @用例名称: bash-builtin-commands +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash 常用内置命令功能,包括 declare、export、readonly、source、eval、trap、getopts、shift 以及 type 等 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" +g_source_file="$g_tmpdir/sourced.sh" + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包,准备 source 用的脚本文件 + assert_true yum install -y bash + cat > "$g_source_file" <<'EOF' +sourced_var="from_source" +sourced_func() { echo "sourced_func_output"; } +EOF + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: 使用 declare -i 声明整型变量 + # @预期结果: 整型变量不允许非数值赋值,数学赋值自动计算 + declare -i int_var=10 + int_var+=5 + assert_true [ "$int_var" -eq 15 ] + + # @测试步骤: 使用 declare -r 声明只读变量 + # @预期结果: 只读变量不能被修改(修改返回非 0) + declare -r readonly_var="immutable" + assert_true [ "$readonly_var" = "immutable" ] + ( readonly_var="changed" ) > /dev/null 2>&1 + assert_true [ $? -ne 0 ] + + # @测试步骤: 使用 export 导出变量到子进程 + # @预期结果: 子进程可以访问被 export 的变量 + export EXPORTED_VAR="exported_value" + result=$(bash -c 'echo $EXPORTED_VAR') + assert_true [ "$result" = "exported_value" ] + + # @测试步骤: 使用 source 加载外部脚本文件 + # @预期结果: 外部脚本中的变量和函数可以被当前 shell 使用 + source "$g_source_file" + assert_true [ "$sourced_var" = "from_source" ] + output=$(sourced_func) + assert_true [ "$output" = "sourced_func_output" ] + + # @测试步骤: 使用 eval 动态执行代码 + # @预期结果: eval 正确执行动态生成的命令 + cmd="result_eval=eval_worked" + eval "$cmd" + assert_true [ "$result_eval" = "eval_worked" ] + + # @测试步骤: 使用 shift 移动位置参数 + # @预期结果: shift 正确移除第一个参数,其余参数前移 + test_shift() { + shift + echo "$1" + } + output=$(test_shift "first" "second" "third") + assert_true [ "$output" = "second" ] + + # @测试步骤: 使用 type 检查命令类型 + # @预期结果: 内置命令被识别为 builtin,外部命令被识别为文件 + type -t echo | grep -q "builtin" + assert_true [ $? -eq 0 ] + type -t ls | grep -q "file" + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 trap 捕获 EXIT 信号 + # @预期结果: 退出时 trap 命令被执行,标记文件被创建 + local trap_flag="$g_tmpdir/trap_flag.txt" + ( + trap "touch $trap_flag" EXIT + exit 0 + ) + assert_true test -f "$trap_flag" + + # @测试步骤: 使用 readonly 限制变量修改 + # @预期结果: readonly 变量的值不能被改变 + readonly RO_VAR="fixed" + assert_true [ "$RO_VAR" = "fixed" ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + unset EXPORTED_VAR + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +############################################################################### diff --git a/bash-c-command-execution.sh b/bash-c-command-execution.sh new file mode 100644 index 0000000000000000000000000000000000000000..1a15428712bcc6ecb172a023ec70c7213f3cb4a8 --- /dev/null +++ b/bash-c-command-execution.sh @@ -0,0 +1,92 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-001-bash-c-command-execution +# @用例名称: bash-c-command-execution +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash -c 选项能够执行字符串命令,包括简单命令、变量展开、命令替换和管道等场景 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包 + assert_true yum install -y bash + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: 使用 bash -c 执行简单 echo 命令 + # @预期结果: 命令执行成功,输出正确 + output=$(bash -c 'echo hello_bash') + assert_true [ $? -eq 0 ] + echo "$output" | grep -q "hello_bash" + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 bash -c 执行包含变量的命令 + # @预期结果: 变量能正确传递和展开 + output=$(bash -c 'var=testval; echo $var') + echo "$output" | grep -q "testval" + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 bash -c 执行命令替换 + # @预期结果: 命令替换结果正确 + output=$(bash -c 'echo $(echo nested)') + echo "$output" | grep -q "nested" + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 bash -c 执行管道命令 + # @预期结果: 管道命令执行成功,输出正确 + output=$(bash -c 'echo "line1\nline2\nline3" | wc -l') + assert_true [ $? -eq 0 ] + [ "$output" -ge 1 ] + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 bash -c 执行算术运算 + # @预期结果: 算术计算结果正确 + output=$(bash -c 'echo $((3 + 4))') + echo "$output" | grep -q "7" + assert_true [ $? -eq 0 ] + + # @测试步骤: bash -c 执行失败命令时返回非 0 退出码 + # @预期结果: 不存在的命令返回非 0 退出码 + bash -c 'command_not_exist_xyz' > /dev/null 2>&1 + assert_true [ $? -ne 0 ] + + # @测试步骤: 使用 bash -c 并通过 $0 $1 传递参数 + # @预期结果: 位置参数正确传递 + output=$(bash -c 'echo $1 $2' bash_test arg1 arg2) + echo "$output" | grep -q "arg1" + assert_true [ $? -eq 0 ] + echo "$output" | grep -q "arg2" + assert_true [ $? -eq 0 ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +############################################################################### diff --git a/bash-conditional-statements.sh b/bash-conditional-statements.sh new file mode 100644 index 0000000000000000000000000000000000000000..efe7935641af610d5070d290dbccbb3b0a0cb650 --- /dev/null +++ b/bash-conditional-statements.sh @@ -0,0 +1,128 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-005-bash-conditional-statements +# @用例名称: bash-conditional-statements +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash 条件语句功能,包括 if/elif/else、case 语句、[[ ]] 扩展测试、文件测试运算符、字符串比较运算符等 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" +g_testfile="$g_tmpdir/testfile.txt" + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包并准备测试文件 + assert_true yum install -y bash + echo "test content" > "$g_testfile" + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: 测试 if/else 基本条件判断 + # @预期结果: 条件为真时执行 if 分支 + val=10 + if [ "$val" -gt 5 ]; then + result="greater" + else + result="not_greater" + fi + assert_true [ "$result" = "greater" ] + + # @测试步骤: 测试 if/elif/else 多分支 + # @预期结果: 正确进入匹配的分支 + score=75 + if [ "$score" -ge 90 ]; then + grade="A" + elif [ "$score" -ge 70 ]; then + grade="B" + else + grade="C" + fi + assert_true [ "$grade" = "B" ] + + # @测试步骤: 使用 [[ ]] 测试字符串匹配(== 通配符) + # @预期结果: 通配符匹配正确 + filename="testfile.txt" + [[ "$filename" == *.txt ]] + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 [[ ]] 测试正则匹配(=~ 运算符) + # @预期结果: 正则表达式匹配正确 + str="hello123" + [[ "$str" =~ ^[a-z]+[0-9]+$ ]] + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 case 语句匹配字符串 + # @预期结果: case 语句正确匹配并执行相应分支 + day="Monday" + case "$day" in + Monday|Tuesday|Wednesday|Thursday|Friday) + dtype="weekday" + ;; + Saturday|Sunday) + dtype="weekend" + ;; + *) + dtype="unknown" + ;; + esac + assert_true [ "$dtype" = "weekday" ] + + # @测试步骤: 测试文件存在性 -f + # @预期结果: 已创建的测试文件被识别为普通文件 + assert_true test -f "$g_testfile" + + # @测试步骤: 测试目录存在性 -d + # @预期结果: 已创建的临时目录被识别为目录 + assert_true test -d "$g_tmpdir" + + # @测试步骤: 测试文件非空 -s + # @预期结果: 有内容的文件 -s 为真 + assert_true test -s "$g_testfile" + + # @测试步骤: 测试字符串非空 -n + # @预期结果: 非空字符串返回真 + nonempty="hello" + assert_true test -n "$nonempty" + + # @测试步骤: 测试字符串为空 -z + # @预期结果: 空字符串返回真 + empty="" + assert_true test -z "$empty" + + # @测试步骤: 测试 && 和 || 逻辑运算符 + # @预期结果: 逻辑与/或运算结果正确 + true && result_and="ok" + assert_true [ "$result_and" = "ok" ] + false || result_or="ok" + assert_true [ "$result_or" = "ok" ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +############################################################################### diff --git a/bash-function-features.sh b/bash-function-features.sh new file mode 100644 index 0000000000000000000000000000000000000000..f794caeccc527f296f26caff7b15d032c417fde2 --- /dev/null +++ b/bash-function-features.sh @@ -0,0 +1,134 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-007-bash-function-features +# @用例名称: bash-function-features +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash 函数功能,包括函数定义、调用、参数传递、返回值、局部变量、递归以及函数作为命令替换等 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" + +# 辅助函数:简单加法 +add_numbers() { + local a="$1" + local b="$2" + echo $((a + b)) +} + +# 辅助函数:判断数字奇偶,返回 0 表示偶数,1 表示奇数 +is_even() { + local n="$1" + [ $((n % 2)) -eq 0 ] +} + +# 辅助函数:递归计算阶乘 +factorial() { + local n="$1" + if [ "$n" -le 1 ]; then + echo 1 + else + local sub + sub=$(factorial $((n - 1))) + echo $((n * sub)) + fi +} + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包 + assert_true yum install -y bash + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: 调用简单函数并通过命令替换捕获输出 + # @预期结果: 函数返回正确的计算结果 + result=$(add_numbers 7 8) + assert_true [ "$result" -eq 15 ] + + # @测试步骤: 函数返回值(return 语句) + # @预期结果: return 返回正确的退出码 + is_even 4 + assert_true [ $? -eq 0 ] + is_even 5 + assert_true [ $? -ne 0 ] + + # @测试步骤: 函数内局部变量不影响外部变量 + # @预期结果: 局部变量作用域仅限函数内部 + outer_var="original" + test_local() { + local outer_var="changed" + echo "$outer_var" + } + inner_output=$(test_local) + assert_true [ "$inner_output" = "changed" ] + assert_true [ "$outer_var" = "original" ] + + # @测试步骤: 函数接收位置参数 $1 $2 $@ + # @预期结果: 位置参数正确传递 + check_params() { + assert_true [ "$1" = "first" ] + assert_true [ "$2" = "second" ] + assert_true [ "$#" -eq 2 ] + } + check_params "first" "second" + + # @测试步骤: 递归函数计算阶乘 + # @预期结果: 递归计算 5! = 120 + result=$(factorial 5) + assert_true [ "$result" -eq 120 ] + + # @测试步骤: 函数可以修改全局变量 + # @预期结果: 全局变量被函数正确修改 + g_counter=0 + increment_counter() { + g_counter=$((g_counter + 1)) + } + increment_counter + increment_counter + increment_counter + assert_true [ "$g_counter" -eq 3 ] + + # @测试步骤: 通过 typeset -f 检查函数是否已定义 + # @预期结果: 已定义的函数可以被 typeset -f 识别 + typeset -f add_numbers > /dev/null 2>&1 + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 unset -f 删除函数定义 + # @预期结果: 删除后函数不再存在 + temp_func() { echo "temp"; } + typeset -f temp_func > /dev/null 2>&1 + assert_true [ $? -eq 0 ] + unset -f temp_func + typeset -f temp_func > /dev/null 2>&1 + assert_true [ $? -ne 0 ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +############################################################################### diff --git a/bash-io-redirection.sh b/bash-io-redirection.sh new file mode 100644 index 0000000000000000000000000000000000000000..01ffc3999d47d2341adecd6158ebb5f9acba46e9 --- /dev/null +++ b/bash-io-redirection.sh @@ -0,0 +1,109 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-008-bash-io-redirection +# @用例名称: bash-io-redirection +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash 输入输出重定向功能,包括标准输出重定向、追加重定向、标准错误重定向、输入重定向、Here Document、Here String 以及管道等 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" +g_outfile="$g_tmpdir/output.txt" + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包 + assert_true yum install -y bash + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: 标准输出重定向到文件(>) + # @预期结果: 文件被创建并包含正确内容 + echo "redirect_test" > "$g_outfile" + assert_true test -f "$g_outfile" + grep -q "redirect_test" "$g_outfile" + assert_true [ $? -eq 0 ] + + # @测试步骤: 追加重定向(>>) + # @预期结果: 内容追加到文件末尾,原内容不被覆盖 + echo "line1" > "$g_outfile" + echo "line2" >> "$g_outfile" + line_count=$(wc -l < "$g_outfile") + assert_true [ "$line_count" -eq 2 ] + + # @测试步骤: 标准错误重定向到文件(2>) + # @预期结果: 错误信息写入指定文件 + local errfile="$g_tmpdir/err.txt" + ls /nonexistent_path_xyz 2> "$errfile" + assert_true test -s "$errfile" + + # @测试步骤: 标准输出和错误合并重定向(2>&1) + # @预期结果: 错误信息和正常输出均写入同一文件 + local combined="$g_tmpdir/combined.txt" + { echo "stdout_msg"; ls /nonexistent_xyz_path; } > "$combined" 2>&1 + grep -q "stdout_msg" "$combined" + assert_true [ $? -eq 0 ] + + # @测试步骤: 输入重定向(<) + # @预期结果: 从文件读取内容作为命令输入 + echo "input_content" > "$g_tmpdir/input.txt" + output=$(cat < "$g_tmpdir/input.txt") + assert_true [ "$output" = "input_content" ] + + # @测试步骤: Here Document(< /dev/null + assert_true [ $? -eq 0 ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +############################################################################### diff --git a/bash-loop-control.sh b/bash-loop-control.sh new file mode 100644 index 0000000000000000000000000000000000000000..3ff401ce78c7130f4fb51192127a2c27dd31503d --- /dev/null +++ b/bash-loop-control.sh @@ -0,0 +1,127 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-006-bash-loop-control +# @用例名称: bash-loop-control +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash 循环控制功能,包括 for 循环、while 循环、until 循环、break/continue 控制以及 C 风格 for 循环等 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包 + assert_true yum install -y bash + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: for 循环遍历列表并累加 + # @预期结果: 循环正确遍历所有元素,累加结果正确 + sum=0 + for i in 1 2 3 4 5; do + sum=$((sum + i)) + done + assert_true [ "$sum" -eq 15 ] + + # @测试步骤: C 风格 for 循环 + # @预期结果: C 风格循环正确执行 + count=0 + for (( i=0; i<5; i++ )); do + count=$((count + 1)) + done + assert_true [ "$count" -eq 5 ] + + # @测试步骤: for 循环使用 {start..end} 序列展开 + # @预期结果: 序列正确展开并循环 + items=() + for n in {1..4}; do + items+=("$n") + done + assert_true [ "${#items[@]}" -eq 4 ] + assert_true [ "${items[3]}" = "4" ] + + # @测试步骤: while 循环 + # @预期结果: while 循环在条件为假时退出,执行次数正确 + counter=0 + while [ "$counter" -lt 5 ]; do + counter=$((counter + 1)) + done + assert_true [ "$counter" -eq 5 ] + + # @测试步骤: until 循环 + # @预期结果: until 循环在条件为真时退出 + val=0 + until [ "$val" -ge 3 ]; do + val=$((val + 1)) + done + assert_true [ "$val" -eq 3 ] + + # @测试步骤: break 跳出循环 + # @预期结果: break 正确跳出循环 + result=0 + for i in 1 2 3 4 5; do + if [ "$i" -eq 3 ]; then + break + fi + result="$i" + done + assert_true [ "$result" -eq 2 ] + + # @测试步骤: continue 跳过本次循环 + # @预期结果: continue 正确跳过偶数,只累加奇数 + odd_sum=0 + for i in 1 2 3 4 5; do + if [ $((i % 2)) -eq 0 ]; then + continue + fi + odd_sum=$((odd_sum + i)) + done + assert_true [ "$odd_sum" -eq 9 ] + + # @测试步骤: for 循环遍历数组 + # @预期结果: 循环正确遍历数组所有元素 + arr=(a b c d) + arr_count=0 + for elem in "${arr[@]}"; do + arr_count=$((arr_count + 1)) + done + assert_true [ "$arr_count" -eq 4 ] + + # @测试步骤: while 循环读取命令输出(while read) + # @预期结果: 正确逐行读取并计数 + line_count=0 + while IFS= read -r line; do + line_count=$((line_count + 1)) + done < <(printf 'line1\nline2\nline3\n') + assert_true [ "$line_count" -eq 3 ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +############################################################################### diff --git a/bash-process-substitution.sh b/bash-process-substitution.sh new file mode 100644 index 0000000000000000000000000000000000000000..bf159032135d6513d4386e10bee55db741146a99 --- /dev/null +++ b/bash-process-substitution.sh @@ -0,0 +1,104 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-010-bash-process-substitution +# @用例名称: bash-process-substitution +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash 进程替换和命令替换功能,包括 $()、反引号、<() 进程替换、>() 进程替换以及子 shell 特性等 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包 + assert_true yum install -y bash + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: $() 命令替换捕获输出 + # @预期结果: 命令输出被正确捕获 + output=$(echo "captured") + assert_true [ "$output" = "captured" ] + + # @测试步骤: 嵌套命令替换 + # @预期结果: 嵌套命令替换正确求值 + output=$(echo $(echo "nested_value")) + assert_true [ "$output" = "nested_value" ] + + # @测试步骤: 命令替换保留多行输出(有换行符) + # @预期结果: 多行输出可以正确捕获并计数 + output=$(printf "a\nb\nc") + line_count=$(echo "$output" | wc -l) + assert_true [ "$line_count" -eq 3 ] + + # @测试步骤: 使用进程替换 <() 比较两个命令的输出 + # @预期结果: 进程替换文件描述符可以被 diff 使用 + diff <(echo -e "a\nb\nc") <(echo -e "a\nb\nc") > /dev/null 2>&1 + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用进程替换 <() 向 while read 传入动态数据 + # @预期结果: 进程替换数据被正确逐行读取 + count=0 + while IFS= read -r line; do + count=$((count + 1)) + done < <(printf "x\ny\nz\n") + assert_true [ "$count" -eq 3 ] + + # @测试步骤: 子 shell () 中修改变量不影响父 shell + # @预期结果: 子 shell 中的变量修改不传播到父 shell + parent_var="parent" + (parent_var="child"; assert_true [ "$parent_var" = "child" ]) + assert_true [ "$parent_var" = "parent" ] + + # @测试步骤: 子 shell 执行后退出码正确传递 + # @预期结果: 子 shell 中命令失败,退出码为非 0 + (exit 1) + assert_true [ $? -ne 0 ] + + # @测试步骤: 使用 {} 组合命令(当前 shell 执行) + # @预期结果: 组合命令在当前 shell 执行,可以修改变量 + group_var=0 + { group_var=42; } + assert_true [ "$group_var" -eq 42 ] + + # @测试步骤: 使用 $$ 获取当前进程 PID + # @预期结果: 当前进程 PID 是有效正整数 + pid=$$ + assert_true [ "$pid" -gt 0 ] + + # @测试步骤: 使用 $? 获取上一命令退出码 + # @预期结果: 成功命令退出码为 0 + true + last_ret=$? + assert_true [ "$last_ret" -eq 0 ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +############################################################################### diff --git a/bash-script-options.sh b/bash-script-options.sh new file mode 100644 index 0000000000000000000000000000000000000000..ca0970b05d59ec53443fa14e669446439fa1415b --- /dev/null +++ b/bash-script-options.sh @@ -0,0 +1,133 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-012-bash-script-options +# @用例名称: bash-script-options +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash 脚本选项功能,包括 set -e(错误退出)、set -u(未定义变量报错)、set -o pipefail(管道错误捕获)、set -x(调试输出)以及 shopt 选项开关等 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包 + assert_true yum install -y bash + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: 测试 set -e 选项(遇错退出),在子 shell 中验证 + # @预期结果: set -e 开启后,命令失败导致子 shell 立即退出 + ( + set -e + false + echo "should_not_reach" + ) > /dev/null 2>&1 + assert_true [ $? -ne 0 ] + + # @测试步骤: 测试 set -u 选项(未定义变量报错),在子 shell 中验证 + # @预期结果: set -u 开启后,访问未定义变量导致错误退出 + ( + set -u + echo "$undefined_variable_xyz" + ) > /dev/null 2>&1 + assert_true [ $? -ne 0 ] + + # @测试步骤: 测试 set -o pipefail 选项 + # @预期结果: 管道中有命令失败时,整个管道返回非 0 + ( + set -o pipefail + false | true + ) > /dev/null 2>&1 + assert_true [ $? -ne 0 ] + + # @测试步骤: 测试 set -x 调试模式(输出命令追踪信息到 stderr) + # @预期结果: set -x 开启后,xtrace 输出到 stderr + local xtrace_output + xtrace_output=$( + set -x + x=1 + ) 2>&1 + echo "$xtrace_output" | grep -q "x=1" + assert_true [ $? -eq 0 ] + + # @测试步骤: 测试 set +e 关闭错误退出选项 + # @预期结果: set +e 关闭后,命令失败不导致脚本退出 + ( + set -e + set +e + false + echo "should_reach" + ) > /dev/null 2>&1 + assert_true [ $? -eq 0 ] + + # @测试步骤: 测试 shopt -s nullglob(无匹配时 glob 展开为空) + # @预期结果: 开启 nullglob 后,不匹配的 glob 展开为空数组而不是原字符串 + ( + shopt -s nullglob + files=( /nonexistent_path_xyz/*.xyz ) + echo "${#files[@]}" + ) > /dev/null 2>&1 + result=$( + shopt -s nullglob + files=( /nonexistent_path_xyz/*.xyz ) + echo "${#files[@]}" + ) + assert_true [ "$result" -eq 0 ] + + # @测试步骤: 测试 shopt -s extglob(扩展 glob 模式) + # @预期结果: extglob 开启后,?(pattern) 等扩展模式可正确匹配 + ( + shopt -s extglob + str="testfile.txt" + [[ "$str" == ?(test)file.txt ]] + ) + assert_true [ $? -eq 0 ] + + # @测试步骤: 验证 bash --version 返回版本信息 + # @预期结果: 命令执行成功并输出包含 bash 的版本信息 + bash --version > /dev/null 2>&1 + assert_true [ $? -eq 0 ] + output=$(bash --version 2>&1) + echo "$output" | grep -qi "bash" + assert_true [ $? -eq 0 ] + + # @测试步骤: 验证 bash -n 语法检查功能 + # @预期结果: 语法正确的脚本返回 0,语法错误返回非 0 + echo 'echo "valid script"' > "$g_tmpdir/valid.sh" + bash -n "$g_tmpdir/valid.sh" + assert_true [ $? -eq 0 ] + + echo 'if [ ; then echo bad; fi' > "$g_tmpdir/invalid.sh" + bash -n "$g_tmpdir/invalid.sh" > /dev/null 2>&1 + assert_true [ $? -ne 0 ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +############################################################################### diff --git a/bash-string-operations.sh b/bash-string-operations.sh new file mode 100644 index 0000000000000000000000000000000000000000..812697d8ce624b2c3b4f0d4c375c49d1e99ae3d4 --- /dev/null +++ b/bash-string-operations.sh @@ -0,0 +1,106 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-009-bash-string-operations +# @用例名称: bash-string-operations +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash 字符串处理功能,包括字符串拼接、比较、查找(grep)、分割(IFS)、printf 格式化以及 read 内置命令读取字符串等 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包 + assert_true yum install -y bash + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: 字符串拼接 + # @预期结果: 拼接结果正确 + str1="hello" + str2="_world" + combined="${str1}${str2}" + assert_true [ "$combined" = "hello_world" ] + + # @测试步骤: 字符串相等比较 + # @预期结果: 相等字符串比较返回真 + assert_true [ "abc" = "abc" ] + + # @测试步骤: 字符串不等比较 + # @预期结果: 不等字符串比较返回真 + assert_true [ "abc" != "xyz" ] + + # @测试步骤: 字符串字典序比较(< 和 >) + # @预期结果: 字典序比较正确 + [[ "apple" < "banana" ]] + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 printf 格式化字符串 + # @预期结果: 格式化输出正确 + output=$(printf "%-10s %05d" "name" 42) + echo "$output" | grep -q "name" + assert_true [ $? -eq 0 ] + echo "$output" | grep -q "00042" + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 IFS 分割字符串 + # @预期结果: 字符串按指定分隔符正确分割 + csv="one,two,three" + IFS=',' read -ra parts <<< "$csv" + assert_true [ "${parts[0]}" = "one" ] + assert_true [ "${parts[1]}" = "two" ] + assert_true [ "${parts[2]}" = "three" ] + + # @测试步骤: 使用 read 从 Here String 读取多个变量 + # @预期结果: read 正确分割并赋值给多个变量 + read -r first second third <<< "aa bb cc" + assert_true [ "$first" = "aa" ] + assert_true [ "$second" = "bb" ] + assert_true [ "$third" = "cc" ] + + # @测试步骤: 字符串包含检查(使用 [[ =~ ]]) + # @预期结果: 子串检查正确 + haystack="the quick brown fox" + [[ "$haystack" =~ "quick" ]] + assert_true [ $? -eq 0 ] + + # @测试步骤: 使用 tr 进行字符转换 + # @预期结果: 字符替换结果正确 + output=$(echo "hello world" | tr ' ' '_') + assert_true [ "$output" = "hello_world" ] + + # @测试步骤: 使用 printf 将数字转十六进制 + # @预期结果: 十六进制转换结果正确 + output=$(printf "%x" 255) + assert_true [ "$output" = "ff" ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +############################################################################### diff --git a/bash-variable-expansion.sh b/bash-variable-expansion.sh new file mode 100644 index 0000000000000000000000000000000000000000..c9513aca33c84144f2aae2df5f3cff89896cc9ea --- /dev/null +++ b/bash-variable-expansion.sh @@ -0,0 +1,113 @@ +#!/bin/bash +############################################################################### +# @用例ID: 20260425-002-bash-variable-expansion +# @用例名称: bash-variable-expansion +# @用例级别: 2 +# @用例标签: bash +# @扩展属性: +# @用例类型: 功能测试 +# @自动化: 1 +# @超时时间: 0 +# @用例描述: 验证 bash 变量展开功能,包括普通变量赋值、默认值展开、字符串截取、字符串替换、大小写转换等 +############################################################################### +if [ -z "$TST_TS_TOPDIR" ]; then + TST_TS_TOPDIR="$(realpath "$(dirname "$0")/..")" + while [ "$TST_TS_TOPDIR" != "/" ]; do + [ -f "${TST_TS_TOPDIR}/tsuite" ] && break + TST_TS_TOPDIR="$(dirname "$TST_TS_TOPDIR")" + done + export TST_TS_TOPDIR +fi +source "${TST_TS_TOPDIR}/common/lib/common.sh" || exit 1 +############################################################################### + +g_tmpdir="$(mktemp -d)" + +tc_setup() { + msg "this is tc_setup" + # @预置条件: 安装 bash 软件包 + assert_true yum install -y bash + return 0 +} + +do_test() { + msg "this is do_test" + + # @测试步骤: 普通变量赋值和展开 + # @预期结果: 变量值正确展开 + myvar="hello" + output="${myvar}" + assert_true [ "$output" = "hello" ] + + # @测试步骤: 使用 ${var:-default} 展开默认值(变量未设置时) + # @预期结果: 返回默认值 + unset undefined_var + output="${undefined_var:-default_value}" + assert_true [ "$output" = "default_value" ] + + # @测试步骤: 使用 ${var:-default} 展开(变量已设置时) + # @预期结果: 返回变量值而非默认值 + set_var="actual" + output="${set_var:-default_value}" + assert_true [ "$output" = "actual" ] + + # @测试步骤: 字符串长度 ${#var} + # @预期结果: 返回正确的字符串长度 + str="hello" + len="${#str}" + assert_true [ "$len" -eq 5 ] + + # @测试步骤: 字符串截取 ${var:offset:length} + # @预期结果: 正确截取子字符串 + str="hello_world" + output="${str:6:5}" + assert_true [ "$output" = "world" ] + + # @测试步骤: 删除前缀匹配 ${var#pattern} + # @预期结果: 正确删除最短前缀 + path="/usr/local/bin" + output="${path#/usr/}" + assert_true [ "$output" = "local/bin" ] + + # @测试步骤: 删除后缀匹配 ${var%pattern} + # @预期结果: 正确删除最短后缀 + filename="test.tar.gz" + output="${filename%.gz}" + assert_true [ "$output" = "test.tar" ] + + # @测试步骤: 字符串替换 ${var/pattern/replacement}(替换第一个) + # @预期结果: 只替换第一个匹配 + str="aabbaa" + output="${str/aa/XX}" + assert_true [ "$output" = "XXbbaa" ] + + # @测试步骤: 字符串全局替换 ${var//pattern/replacement} + # @预期结果: 替换所有匹配 + str="aabbaa" + output="${str//aa/XX}" + assert_true [ "$output" = "XXbbXX" ] + + # @测试步骤: 大写转换 ${var^^} + # @预期结果: 字符串全部转换为大写 + str="hello" + output="${str^^}" + assert_true [ "$output" = "HELLO" ] + + # @测试步骤: 小写转换 ${var,,} + # @预期结果: 字符串全部转换为小写 + str="HELLO" + output="${str,,}" + assert_true [ "$output" = "hello" ] + + return 0 +} + +tc_teardown() { + msg "this is tc_teardown" + rm -rfv "$g_tmpdir" || return 1 + return 0 +} + +############################################################################### +tst_main "$@" +###############################################################################