繁体   English   中英

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

[英]How do I pipe to terminal and to program at the same time in 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程序?

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

怎么样简单

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

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

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

当以下脚本检测到它在标准输入的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

如果您的目标程序( 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')

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM