6

我对编写脚本非常陌生,并且无法弄清楚如何开始使用 bash 脚本,该脚本将根据预期输出自动测试程序的输出。

我想编写一个 bash 脚本,该脚本将在一组测试输入上运行指定的可执行文件,比如 in1 in2 等,针对相应的预期输出,out1、out2 等,并检查它们是否匹配。要测试的文件从标准输入读取其输入并将其输出写入标准输出。因此在输入文件上执行测试程序将涉及 I/O 重定向。

该脚本将使用单个参数调用,该参数将是要测试的可执行文件的名称。

我在进行此操作时遇到了麻烦,因此将不胜感激任何帮助(指向进一步解释我如何做到这一点的任何资源的链接)。我显然已经尝试过搜索自己,但并没有很成功。

谢谢!

4

5 回答 5

10

如果我得到你想要的;这可能会让你开始:

bash + diff 等外部工具的组合。

#!/bin/bash

# If number of arguments less then 1; print usage and exit
if [ $# -lt 1 ]; then
    printf "Usage: %s <application>\n" "$0" >&2
    exit 1
fi

bin="$1"           # The application (from command arg)
diff="diff -iad"   # Diff command, or what ever

# An array, do not have to declare it, but is supposedly faster
declare -a file_base=("file1" "file2" "file3")

# Loop the array
for file in "${file_base[@]}"; do
    # Padd file_base with suffixes
    file_in="$file.in"             # The in file
    file_out_val="$file.out"       # The out file to check against
    file_out_tst="$file.out.tst"   # The outfile from test application

    # Validate infile exists (do the same for out validate file)
    if [ ! -f "$file_in" ]; then
        printf "In file %s is missing\n" "$file_in"
        continue;
    fi
    if [ ! -f "$file_out_val" ]; then
        printf "Validation file %s is missing\n" "$file_out_val"
        continue;
    fi

    printf "Testing against %s\n" "$file_in"

    # Run application, redirect in file to app, and output to out file
    "./$bin" < "$file_in" > "$file_out_tst"

    # Execute diff
    $diff "$file_out_tst" "$file_out_val"


    # Check exit code from previous command (ie diff)
    # We need to add this to a variable else we can't print it
    # as it will be changed by the if [
    # Iff not 0 then the files differ (at least with diff)
    e_code=$?
    if [ $e_code != 0 ]; then
            printf "TEST FAIL : %d\n" "$e_code"
    else
            printf "TEST OK!\n"
    fi

    # Pause by prompt
    read -p "Enter a to abort, anything else to continue: " input_data
    # Iff input is "a" then abort
    [ "$input_data" == "a" ] && break

done

# Clean exit with status 0
exit 0

编辑。

添加退出代码检查;和一小段步行槽:

简而言之,这将:

  1. 检查是否给出参数(bin/application)
  2. 使用“基本名称”数组,循环并生成真实文件名。
    • 即:有数组("file1" "file2")你得到
      • 在文件中:file1.in
      • 要验证的输出文件:file1.out
      • 输出文件:file1.out.tst
      • 在文件中:file2.in
      • ...
  3. 执行应用程序并在文件中重定向到stdin应用程序<,并stdout从应用程序重定向到输出文件测试>
  4. 使用像 ie 这样的工具diff来测试它们是否相同。
  5. 检查工具的退出/返回代码并打印消息 (FAIL/OK)
  6. 提示继续。

任何和所有偏离路线的东西都可以修改、删除等。


一些链接:

于 2012-04-12T07:07:15.500 回答
2

Expect可能非常适合此类问题:

Expect 是一个主要用于自动化交互式应用程序的工具,例如 telnet、ftp、passwd、fsck、rlogin、tip 等。Expect 确实使这些东西变得微不足道。Expect 也可用于测试这些相同的应用程序。

于 2012-04-12T06:32:44.083 回答
0

首先看一下 Advanced Bash-Scripting Guide 关于I/O 重定向的章节。

然后我不得不问为什么要使用 bash 脚本?直接从您的 makefile 中执行此操作。

例如,我有一个通用的 makefile,其中包含以下内容:

# type 'make test' to run a test.
# for example this runs your program with jackjill.txt as input
# and redirects the stdout to the file jackjill.out
test: $(program_NAME)
        ./$(program_NAME) < jackjill.txt > jackjill.out
        ./diff -q jackjill.out jackjill.expected

您可以像这样添加任意数量的测试。您每次只需将输出文件与包含预期输出的文件进行比较。

当然,这仅在您实际使用生成文件来构建程序时才有意义。:-)

于 2012-04-12T07:20:44.060 回答
0

功能。这里的字符串。重定向。过程替换。diff -q. test.

于 2012-04-12T06:25:10.720 回答
0

预期输出是第二种输入。

例如,如果您想测试一个平方函数,您的输入应为 (0, 1, 2, -1, -2),预期输出为 (0, 1, 4, 1, 4)。

然后,您会将输入的每个结果与预期的输出进行比较并报告错误。

您可以使用数组:

in=(0 1 2 -1 -2)
out=(0 1 4 2 4)

for i in $(seq 0 $((${#in[@]}-1)) )
do
   (( ${in[i]} * ${in[i]} - ${out[i]} )) && echo -n bad" " || echo -n fine" "
   echo $i ": " ${in[i]}"² ?= " ${out[i]}
done

fine 0 :  0² ?=  0
fine 1 :  1² ?=  1
fine 2 :  2² ?=  4
bad 3 :  -1² ?=  2
fine 4 :  -2² ?=  4

当然,您可以从文件中读取两个数组。

使用 (( ... )) 进行测试可以调用算术表达式、字符串和文件。尝试

 help test 

概览。

从文件中逐字读取字符串:

for n in $(< f1); do echo $n "-" ; done

读入一个数组:

arr=($(< file1)) 

逐行读取文件:

for i in $(seq 1 $(cat file1 | wc -l ))
do
    line=$(sed -n ${i}p file1)
    echo $line"#"
done 

针对程序输出进行测试听起来像是字符串比较和程序输出捕获n=$(cmd param1 param2)

asux:~/prompt > echo -e "foo\nbar\nbaz" 
foo
bar
baz
asux:~/prompt > echo -e "foo\nbar\nbaz" > file 
asux:~/prompt > for i in $(seq 1 3); do line=$(sed -n ${i}p file); test "$line" = "bar" && echo match || echo fail ; done 
fail
match
fail

进一步有用:在 [[ ... ]] 括号中使用 =~ 对字符串进行正则表达式匹配:

for i in $(seq 1 3)
do
   line=$(sed -n ${i}p file)
   echo -n $line
   if [[ "$line" =~ ba. ]]; then
     echo " "match
   else echo " "fail
   fi
done 
foo fail
bar match
baz match
于 2012-04-12T06:53:55.350 回答