如何在bash中管道终端和同时编程

时间:2016-10-13 01:07:46

标签: c bash

所以我试图创建一个脚本来自动化我的C程序的测试(进出),我试图让输入保持在屏幕上,所以我知道发生了什么。

到目前为止我只尝试过管道:

foo < input.txt

cat input.txt | tee dev/tty |foo

还没有为我工作。

所以假设输入文件看起来像:

123
321

理想情况下,IO看起来像:

Input: 123
Echo: 123
Input: 321
Echo: 321

但它变成了

123
321
Input: 
Echo: 123
Input: 
Echo: 321

我可以使用其他方法来测试我的C程序吗?我可以在哪里开球可以达到这样的效果?我是否可以编写另一个可以实现类似功能的C程序?

4 个答案:

答案 0 :(得分:1)

tee的stdout(到foo的stdin)和重复的写入(到你的tty字符开发)不会及时同步。你的tty比foo更快地消耗输入,并且libc的缓冲使它更糟糕。如果您正在寻找交互式自动化,请查看expect程序。

答案 1 :(得分:0)

如何简单地

cat input.txt ; cat input.txt | foo ;

第一部分打印输入,第二部分打印输出。

您可以选择将print语句放在代码中,以便在每次迭代时在相关输出之前打印正在处理的输入的子部分。

答案 2 :(得分:0)

以下脚本在检测到标准输入上的read()系统调用被阻止时,会向程序输入输入,并在标准输出上打印相同的文本。结果,程序的输出和标准输入的内容被正确交错。

<强>用法:

$ simulate_user_input program args ...

示例:

$ cat > test_script <<'END'
#!/usr/bin/env bash
echo -n "First name: "
read -r first_name
echo -n "Second name: "
read -r second_name
echo "Hello $first_name $second_name"
END                                  

$ chmod +x test_script
$ ./simulate_user_input ./test_script <<< $'John\nSmith'
First name: John
Second name: Smith
Hello John Smith

<强> simulate_user_input

#!/usr/bin/env bash

if [ $# -eq 0 ]
then
    cat<<END

Usage:

    $(basename "$0") command args ...

END
    exit 1
fi

#set -x
if [ "$1" == "-simulate" ]
then
    app_stdin="$2/app_stdin"
    user_stdin="$2/user_stdin"
    user_stdout="$2/user_stdout"
    exec > "$app_stdin" 3< "$user_stdin" 4> "$user_stdout"
    while read -r -n 6 -t 0.1 line
    do
        if [[ $line == 'read(0' ]]
        then
            read -u 3 -r line || { cat > /dev/null; exit 0; }
            echo "$line" >&4
            echo "$line"
        fi
    done
    exit 0
fi

cleanup()
{
    rm -rf "$tmpdir"
    if [ "$(jobs -r|wc -l)" -ne 0 ]
    then
        kill %1 %2
    fi
}

tmpdir="$(mktemp -d)"
trap "cleanup" EXIT
app_stdin="$tmpdir/app_stdin"
user_stdin="$tmpdir/user_stdin"
user_stdout="$tmpdir/user_stdout"
mkfifo "$app_stdin"
mkfifo "$user_stdin"
mkfifo "$user_stdout"

cat "$app_stdin"|strace -e read -o "|$0 -simulate '$tmpdir'" "$@" &
cat < "$user_stdout" &
cat > "$user_stdin"
wait

答案 3 :(得分:0)

如果您的目标程序(foo)保证为每行输入输出一行,这是一个可以执行此操作的Python 2程序:

#!/usr/bin/env python
import sys, subprocess
sp = subprocess.Popen(sys.argv[1:], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
for input_line in sys.stdin:
    print('Input: ' + input_line.rstrip('\r\n'))
    sp.stdin.write(input_line)
    sp.stdin.flush()
    output_line = sp.stdout.readline()
    print('Output: ' + output_line.rstrip('\r\n'))

如果将其另存为tee.py,则可以使用

进行测试
echo -e '123\n321' | tee.py cat -

用于通用的可重复测试,或

echo -e '123\n321' | tee.py foo

您的具体示例。

PS:如果你想在Python 3中使用它,你必须改变两行:

    sp.stdin.write(input_line.encode('utf-8'))

    output_line = sp.stdout.readline().decode('utf-8')