【问题标题】:Syntax for subprocess.call (Win7 x64)subprocess.call 的语法 (Win7 x64)
【发布时间】:2012-11-18 04:44:33
【问题描述】:

我正在尝试使用 subprocess.call() 调用不在本地 Python 目录中的 .exe 文件。命令(我在 cmd.exe 中输入)如下:"C:\Program Files\R\R-2.15.2\bin\Rscript.exe" --vanilla C:\python\buyback_parse_guide.r

脚本运行,执行我需要做的事情,并且我已确认输出正确。

这是我的 python 代码,我认为它会做同样的事情:

## Set Rcmd
Rcmd = r'"C:\Program Files\R\R-2.15.2\bin\Rscript.exe"'
## Set Rargs
Rargs = r'--vanilla C:\python\buyback_parse_guide.r'

retval = subprocess.call([Rcmd,Rargs],shell=True)

当我在 Python 控制台中调用 retval 时,它返回 1 并且 .R 脚本没有运行,但我没有收到任何错误。我很确定这是一个非常简单的语法错误...帮助?非常感谢!

【问题讨论】:

  • 文件路径中的空格可能会导致问题。将 R 安装在没有空格的目录路径中。
  • 我不知道这是什么原因,但我会尝试将安装移动到不同的目录并报告回来。谢谢。
  • 我将我的 R 安装移动到一个没有空格的文件夹,重新尝试,仍然没有。
  • 如果您cd 进入 Python 脚本所在的目录而不是 R 脚本所在的目录,命令行是否有效?
  • 您是否尝试过使用 os.system 而不是 wim 建议的 subprocess.call? (这不是一个好的修复,但它是一个很好的调试步骤。)你能把一些日志记录到 R 脚本中,看看为什么它会提前返回吗?或者使用--verbose 运行它?

标签: python r python-2.7 subprocess


【解决方案1】:

根据the docs,Rscript:

... 是 #! 中使用的替代前端。脚本和其他脚本应用程序。

…方便写#!脚本……(标准的 Windows 命令行没有 #! 脚本的概念,但 Cygwin shell 有。)

… 仅在具有 execv 系统调用的系统上受支持。

所以,这不是在 Windows 下从另一个程序运行 R 脚本的方式。

This answer 说:

Rscript.exe 是批处理脚本的好帮手……对于其他一切,还有 R.exe

因此,除非您有充分的理由在批处理脚本之外使用 Rscript,否则您应该切换到 R.exe。

您可能想知道为什么它可以在 cmd.exe 下运行,但不能在 Python 下运行。我不知道答案,我认为不值得通过代码挖掘或尝试找出答案,但我可以做出一些猜测。

一种可能性是,当您从命令行运行时,这是一个控制终端的cmd.exe,而当您从subprocess.call(shell=True)os.system 运行时,这是一个无头cmd.exe。运行 .bat/.cmd 批处理文件可以获得非无头 cmd,但直接从另一个应用程序运行 cmd 不会。 R 历来处理 Windows 终端的各种复杂性,这就是为什么他们曾经有单独的 Rterm.exe 和 Rcmd.exe 工具。如今,它们都合并到了 R.exe 中,无论哪种方式都应该可以正常工作。但是,如果您尝试做文档说不做的事情,那可能没有经过测试,它可能不起作用是完全合理的。

无论如何,它为什么在某些情况下工作并不重要,即使它没有记录在案。这当然并不意味着它应该在没有记录的其他情况下工作,或者你应该试图强迫它这样做。只要做正确的事并运行R.exe 而不是Rscript.exe

除非您的某些信息与我在文档中找到的所有内容以及我能找到的所有其他内容相矛盾,否则我会把钱放在 Rscript.exe 本身就是问题所在。

您必须阅读有关Rscript.exeR.exe 之间调用差异的文档,但它们并不相同。根据the intro docs,:

如果你只想运行一个文件 foo.R 的 R 命令,推荐的方式是使用 R CMD BATCH foo.R

根据您上面的评论:

当我在 cmd.exe 中键入“C:\R\R-2.15.2\bin\i386\R.exe” CMD BATCH C:\python\buyback_parse_guide.r 时,.R 脚本运行成功。将其传递给 python 的正确语法是什么?

这取决于平台。在 Windows 上,参数列表会变成一个字符串,所以你最好只使用一个字符串,这样你就不必调试连接;在 Unix 上,一个字符串被分割成一个参数列表,所以你最好使用一个列表,这样你就不必调试连接了。

由于路径中没有空格,所以我会去掉引号。

所以:

rcmd = r'C:\R\R-2.15.2\bin\i386\R.exe CMD BATCH C:\python\buyback_parse_guide.r'
retval = subprocess.call(rcmd)

【讨论】:

  • 谢谢。看起来Rscript.exe 不是要走的路。仍在尝试使用R.exe 来降低语法......
【解决方案2】:

引用the docs

如果 shell 为 True,建议将 args 作为字符串而不是序列传递。

拆分它(手动或通过shlex)只是让subprocess 可以重新组合它们以便shell 可以再次拆分它们是愚蠢的。

我不确定你为什么认为你需要shell=True。 (如果没有充分的理由,一般是不想要的……)但即使没有shell=True

在 Windows 上,如果 args 是一个序列,它将按照在 Windows 上将参数序列转换为字符串中所述的方式转换为字符串。这是因为底层的 CreateProcess() 对字符串进行操作。

所以,只需给 shell 命令行:

Rcmd = r'"C:\Program Files\R\R-2.15.2\bin\Rscript.exe" --vanilla C:\python\buyback_parse_guide.r'
retval = subprocess.call(Rcmd, shell=True)

【讨论】:

  • 我在上面试过你的code-sn-p。调用retval,它仍然返回1。 .R 脚本没有运行。 :?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-13
  • 1970-01-01
  • 1970-01-01
  • 2018-01-27
  • 2012-02-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多