子流程运行/调用不起作用

时间:2018-06-27 18:42:05

标签: python python-3.x terminal subprocess

我想在我的Python代码中使用“ raster2pgsql”实用程序。当我在Linux终端中使用它时,它可以正常工作。这是命令:

$ raster2pgsql -a "/mnt/c/Users/Jan/path/to/raster/dem.tiff" test_schema.raster2 | psql -h localhost -d pisl -U pisl

然后,我使用subprocess.run(我也尝试过subprocess.call)在我的Python代码中使用相同的工具。这是我的代码:

from subprocess import run
command = ["raster2pgsql", "-a", '"' + file_name + '"', self.schema_name +  "." + identifier, "|", "psql", "-h", "localhost", "-p", "5432", "-d", self.dbname]
run(command)

我收到此错误:

ERROR: Unable to read raster file: "/mnt/c/Users/Jan/path/to/raster/dem.tiff"

打印command给出了我认为正确的信息(相当于终端中的工作方式):

['raster2pgsql', '-a', '"/mnt/c/Users/Jan/path/to/raster/dem.tiff"', 'test_schema.raster2', '|', 'psql', '-h', 'localhost', '-p', '5432', '-d', 'pisl']

我已经仔细检查了栅格文件的路径是否正确,尝试使用单引号,双引号,但没有任何帮助。我看过许多类似的问题(hereherehere),但没有发现任何帮助。

我在Windows 10中使用Python 3.5和Linux Bash Shell。

问题:我使用子流程的方式有什么问题?

1 个答案:

答案 0 :(得分:3)

2个问题:

  • 无需额外引用文件名。它实际上是传递给系统的,因为没有名为"/tmp/something"的文件,所以命令失败。
  • 第二秒,要通过管道,您需要shell=True

如此快捷的解决方法:

command = ["raster2pgsql", "-a", file_name, self.schema_name +  "." + identifier, "|", "psql", "-h", "localhost", "-p", "5432", "-d", self.dbname]
run(command,shell=True)

或使用命令字符串(因为shell=True对参数列表很挑剔)

command = "raster2pgsql -a "+ file_name + " " + self.schema_name +  "." + identifier + " | psql -h localhost -p 5432 -d" + self.dbname
run(command,shell=True)

(丑陋,不是吗?)

最好在没有shell=True的情况下运行2个进程,并使用python将它们通过管道连接在一起,从而更加可移植和安全(不确定shell=True在Linux上如何与参数列表交互) ):

from subprocess import *
command1 = ["raster2pgsql", "-a", file_name, self.schema_name +  "." + identifier]
p = Popen(command1,stdout=PIPE)
command2 = ["psql", "-h", "localhost", "-p", "5432", "-d", self.dbname]
run(command2,stdin=p.stdout)

创建的第一个Popen对象将其输出写入管道(由于stdout=PIPE参数)。 run函数也可以将输入作为管道(由于stdin=p.stout)。它消耗了第一个命令的输出,从而创建了本机管道命令链,而无需使用shell(以及引号,空格,特殊字符解释等注意事项...)