所以我有一个程序,它接受用户输入并根据输入输出文本。
EDIT2:我想创建一个运行 C 可执行文件的脚本,该脚本从文件提供 C 程序输入并将输出重定向到另一个文件。但是,每当为输入打印输出时,我也想打印出输入,基本上将输入和输出组合/合并在一起。因此,我在文件中逐行输入输入,然后将每个输入的输出打印到文件中,并且我继续这样做。我不想重新运行该程序,我希望该程序仍然运行,直到它到达输入文件的末尾或直到我从脚本向它发送终止信号。 (我正在尝试为班级制作一个评分脚本。学生提交他们的程序,我运行这个脚本,并向他们的程序提供输入,但我想一起跟踪输入+输出,这样我就可以更轻松地跟踪每个输出的输入)我可以弄清楚如何自己创建脚本的其余部分,但我只是坚持将输入+输出组合在一起。
Edit3:我认为expect不会起作用,因为我无法知道程序会输出什么。我只知道它应该接受什么。例如,一个学生可能有一个程序说“给我一个字符:”,而另一个学生会说“输入一个字符-”,所以我不知道这些程序会发生什么。
(注意:我将有许多不同的可执行文件,它们具有不同的格式,但都应该要求相同数量的输入)
例如,可执行文件之一可能是这样的:
"Enter a number: " (Wait for user input)
"Give another: " (Wait for user input
"Total: " (Output based on input)
"Do you want to run again? "(Wait for user input)
编辑:我的脚本的主要目标是运行程序,逐行从文件中获取输入。例如,对于这个程序,我希望它将文件“输入”作为标准输入,但我也想跟踪与标准输出合并的标准输入。
所以我知道./a.out<input>output会输出
Enter a number:
Give another:
Total: 15
Do you want to run again?
然而,它缺少我想要包含的输入,因此我只需查看输出文件就可以根据输出判断输入是什么,因为输入可能是 7 8 N 或 5 10 N 或类似的东西。
答案1
如果我理解正确,您想要检测何时a.out
从标准输入读取数据,以及何时发送该数据并将该数据写入同一个日志文件 stdout 被重定向到echo
以交互运行时模拟本地终端?
那么解决方案(bash 语法)可能是这样的:
mkfifo strace.fifo
{
while read -d, trace; do
if [[ $trace = *"read(0" ]]; then
IFS= read -rn1 answer <&3 || break
answer=${answer:-$'\n'}
printf %s "$answer" >&2
printf %s "$answer"
fi
done < strace.fifo 3< answers.txt |
strace -o strace.fifo -e read ./a.out
} > log 2>&1
这个想法是使用strace
(假设您使用的是 Linux)来跟踪read
系统调用,并且每当文件描述符 0 存在时read
,一次从answers.txt
.
编辑:如果程序使用 stdio 或类似的东西。当输出被重定向到常规文件并且不再是终端时,可能发生的情况是它输出的所有提示都被缓冲,并且仅在程序退出时才会刷新。
解决方法是使用stdbuf
: 替换./a.out
为stdbuf -oL ./a.out
。这将告诉应用程序(假设它是动态链接的应用程序并且缓冲是由于 stdio)在 stdout 上进行行缓冲,就像它是终端一样。然而,它仍然不会做的是在从 stdin 读取 stdio 时刷新 stdout,如果 stdin/stdout 是终端,它通常会这样做。例如,在显式fflush
或最终写入换行符之前,不会显示未以换行符终止的提示。因此最好的方法可能是stdbuf -o0
完全禁用缓冲。
如果a.out
可以分叉进程或线程,请将该-f
选项添加到strace
.
如果应用程序在select
实际poll
执行read
.非阻塞 I/O 也可能导致我们发送数据过快。
正如评论中提到的。expect
是模拟用户交互的工具,它使用伪终端,所以你会自动获得输入回显并且不会有缓冲输出问题。作为 的替代方案stdbuf
,您可以使用它unbuffer
附带的脚本来包装a.out
伪终端。在这种情况下,您可能需要在检测读取和发送答案之间添加一点延迟,以便expect
在其标准输出上重现提示。
答案2
用于script
此。这正是它的用途。
script /tmp/logfile -c 'your command here'
例如:
>> script /tmp/log -c 'read -p "Value: " value; echo "value=$value"'
Script started, file is /tmp/log
Value: foo
value=foo
Script done, file is /tmp/log
>> cat /tmp/log
Script started on Wed 01 May 2013 01:16:34 PM EDT
Value: foo
value=foo
Script done on Wed 01 May 2013 01:16:35 PM EDT