shell脚本,用输入执行程序并保存输入和输出中的输出

时间:2017-12-15 11:12:41

标签: python linux bash shell

我正在开发一个分配服务器,学生可以上传他们的程序解决方案。它应该可以使用几种编程语言。为了测试程序,我正在执行一个shell脚本,并将测试用例和文件作为参数传递:

printf '10\n3\n+\n' | ./eval_python steps.py

它的工作,这不是问题。对于输出我得到类似的东西:

使用shell脚本运行python脚本:

$ How much steps? Step size? Counting up (+) or down (-) ? Step   0:     3
$ Step   1:     6
$ Step   2:     9
$ Step   3:    12
$ Step   4:    15
$ [..]

这种格式使得评估非常困难,也可能使学生感到困惑,因为他们没有看到输入(当你从shell运行python脚本时,输出看起来像下面的例子)。对于评估难度,学生不得像在此解决方案中那样命名他们的输入,如果他们只是问Steps?而不是How much steps?,那也没关系。

直接从shell运行python脚本:

$ How much steps?  10
$ Step size? 3
$ Counting up (+) or down (-)? +
$ Step   0:     3
$ Step   1:     6
$ Step   2:     9
$ Step   3:    12
$ Step   4:    15
$ [..]

有没有办法在输出中组合输入?或者其他想法如何解决这个问题?

非常感谢!

3 个答案:

答案 0 :(得分:1)

自动处理用户提示比看上去困难,遗憾的是printf不足以完全模拟它。如果您不想触及python代码本身,则可能必须使用expect,这是一种用于处理交互式程序的脚本语言。

如果您的系统上没有(可能),请使用sudo apt install expectsudo yum install expect进行安装。我在这里的这个粗糙的东西应该能够满足你的要求:

<强> expect_script.exp

#!/usr/bin/expect -f

set steps [lindex $argv 0]
set size [lindex $argv 1]
set plus_or_minus [lindex $argv 2]
set script_name [lindex $argv 3]

spawn python3 ${script_name}
# Or `spawn eval_python ${script_name}`, as long as it is a python 3 interpreter as well
# If it is python 2, all `input` calls within need to be changed to `raw_input`

expect "steps"
send -- "${steps}\r"
expect "size"
send -- "${size}\r"
expect "Counting"
send -- "${plus_or_minus}\r"
expect eof

然后像这样称呼它:

./expect_script.exp 10 3 + steps.py

如果您对语法或语义有疑问,请随时提出。但是不要期待太多(哈哈),我不是很擅长奇怪的Unix工具。

使用可变数量的参数进行编辑:

<强> expect_script.exp

#!/usr/bin/expect -f

spawn python3 [lindex $argv 0]
# Or `spawn eval_python [lindex $argv 0]`, as long as it is a python 3 interpreter as
# well. If it is python 2, all `input` calls within need to be changed to `raw_input`.

set sleep_time 0.1  # using `sleep` to wait for the next prompt is, usually,
                    # a very bad idea. Maybe you can control your input calls
                    # by including unique identifiers in them, such as 1, 2, 3..
                    # and using `except` to properly wait for them?

for {set i 1} {$i < [llength $argv]} {incr i 1} {
 sleep $sleep_time  
 send -- [lindex $argv $i]\r
}
expect eof

调用顺序已更改,因为我们需要在以参与方式发送参数之前调用我们的python脚本:

./expect_script.exp test.py 10 3 +

或者,更改python脚本以接受命令行参数。如果您计划执行任务自动化,或重复使用代码,或者只是一般 - 命令行参数几乎总是比用户提示更好。本机python ArgParse模块非常好,即使你不想重写当前的代码,它仍然值得研究并尝试将来应用它。

答案 1 :(得分:0)

可以使所有流“需求驱动”,但这不是一项微不足道的任务,尤其是脚本编写。我的意思是,当管道说它需要更多输入时,每个输入字符串只传递给管道。同样,您必须在准备好后立即收集输出。 通过这样做,您可以在消耗它们时组合输入和输出流,以便制作合理的报告。

请注意,您可能需要注入一些新行,以使其真正可读。

答案 2 :(得分:0)

也许不同的方法是告诉用户他们必须提出具体问题。

让你的线束按字符(我知道)读取输出字符,并且一旦它完全匹配特定的预期问题,它就会将匹配的答案作为输入注入,但每次匹配只注入一次。当然,一旦满足所有问题,您就可以切换到更快的批量读取。

然后,您可以按字节输出流式传输,并以自然顺序将注入的响应传输到日志文件,该顺序与您的线束正在执行的操作相匹配。对于线束来说,暂停并打印未消耗的问题作为诊断辅助可能是有益的。

这允许提到的问题排序,可选问题等,但是将设计规范的一部分硬连接到客户要求。向学生明确表示,如果与自动处理器的提示不匹配,或者说提供本地语言翻译的客户,他们将失去分数。