我有一个程序,其中包含一个小文件结构,然后使用
运行python do_work.py foo bar
我希望我的Rails用户按下按钮并为他们发生这种情况,结果要么上传到某个地方,要么只是作为下载链接或类似的东西抛出 - do_work.py
的输出(比如说,它是result.txt
)
我还想澄清一下,脚本导致在文件系统上创建3个独立的文件,这些文件不是文本文件(这应该不重要,这里不是问题)
最好的方法是什么?可以rake运行exec Python吗?更重要的是,这在heroku上是可行的吗?
我在我的系统上安装了Python,但sockmonk提供的答案似乎不起作用 - 它返回nil。请注意,ls
等其他命令似乎有效。
这可能是权限问题吗?
def index
value = %x( python --version )
render :text => value
end
顺便说一下,在irb
中尝试此操作:
%x(python)
打开irb的Python终端INSIDE。无论出于什么原因,它都不会占用参数。
答案 0 :(得分:26)
您的index
方法不起作用,因为python --version
将其版本输出到STDERR,而不是STDOUT。如果您不需要分离这些流,则可以将STDERR重定向到STDOUT:
value = %x(python --version 2>&1)
此调用是同步的,因此在运行脚本(python do_work.py foo bar 2>&1
)之后,您应该能够读取它生成的文件。
如果脚本由于某种原因无法创建文件,您现在将在value
变量中看到异常,因为错误消息通常会发送到STDERR。
如果要将STDERR与STDOUT分开,请使用Open3模块。
请注意脚本需要一些时间才能运行,因此调用可能会重叠。我会在这里使用一个队列来阻止这种情况。
不要忘记检查用户输入的数据。永远不要将它直接传递给脚本。
答案 1 :(得分:4)
部分取决于数据的格式。如果它不是太长并且可以直接在浏览器中呈现,您可以在rails控制器中执行类似的操作:
result = `python do_work.py foo bar`
render :text => result
假设结果是纯ASCII文本,结果将直接显示在浏览器中。如果do_work.py的参数来自用户,你必须首先验证它们,所以你最终不会为自己创建一个讨厌的漏洞。在这种情况下,使用system()调用可能会更安全。
如果要将结果作为文件发回,请查看ruby的Tempfile类以创建文件(以不会永远存在的方式),并使用rails的send_file和send_data命令发送一些不同的选项以这种方式支持结果。
答案 2 :(得分:3)
utapyngo的回答几乎涵盖了你需要知道的全部内容。我会回答这一部分:
顺便说一下,在irb中尝试这个: %×(蟒) 打开irb的python终端INSIDE。无论出于什么原因,它都不会占用参数。
要将参数传递给python脚本,只需传递它即可。例如:
[fotanus@thing ~]$ python a.py
args:
['a.py']
[fotanus@thing ~]$ irb
1.8.7 :001 > %x(python a.py foo bar)
=> "args:\n['a.py', 'foo', 'bar']\n"
这适用于ruby 1.8,1.9和2.0。
答案 3 :(得分:1)
这取决于你想要整合python脚本的深度。有一些方法可以直接从ruby中调用python模块。
http://www.goto.info.waseda.ac.jp/~fukusima/ruby/python-e.html
这样可以直接从python脚本获取输出,而不是通过I / O设备。
答案 4 :(得分:1)
我会做以下事情。
在后台异步执行此任务。一旦结果准备就绪,报告给用户。
使用Open3和delayed_job gem。
可以实现这一目标在Open3模块中查看popen3方法。
Open3.popen3([env,] cmd... [, opts]) {|stdin, stdout, stderr, wait_thr|
pid = wait_thr.pid # pid of the started process.
...
exit_status = wait_thr.value # Process::Status object returned.
}
在您的情况下,您可以将Open3.popen3
语句更改为以下内容
Open3.popen3("python do_work.py foo bar"){
...
# mechanism for reporting like setting a flag in database system
# or queue system
}
注意:您应该提供python脚本的完整路径
然后使用delayed_job gem将其作为后台任务运行。
您还应该有一个轮询机制,它将轮询系统以查看是否设置了标志,这意味着结果已准备就绪,然后将其提供给用户。