【问题标题】:Subprocess run/call not working子进程运行/调用不起作用
【发布时间】:2018-12-06 17:53:06
【问题描述】:

我想在我的 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。

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

【问题讨论】:

  • 你为什么要引用文件名?
  • 因为当我不识别文件名时它无法识别。当我删除引号时,它认为“test_schema.raster2”是文件名。
  • 我提供了另一种方法,将 2 个命令连接在一起。请测试一下。如果有错误,请准确报告。我怀疑引号是问题所在,因为 shell 在您执行的工作命令中删除了它们。

标签: python python-3.x terminal subprocess


【解决方案1】:

这里有 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(以及引用的警告,空格、特殊字符解释等...)

【讨论】:

  • 感谢您的解释。我试图让 py 3 脚本运行 py 2 脚本,我使用 process = subprocess.run(['py', '-2', os.path.basename(latest_file)]) 但由于某种原因它没有运行。我不小心来了,通过在不同的行中添加shell=True,它可以工作。你有机会知道它为什么起作用吗?非常感谢!
  • 您的意思是 subprocess.run(['py', '-2', os.path.basename(latest_file)],shell=True) 运行并且没有 shell=True 不是吗?这很可能是另一个要问的问题。
  • 哦,恰恰相反。在一行中它没有工作。但是以您提出的“脏”格式:command = ['py', '-2', os.path.basename(latest_file)] subprocess.run(command, shell=True)it 有效。
猜你喜欢
  • 1970-01-01
  • 2014-10-14
  • 1970-01-01
  • 1970-01-01
  • 2016-11-02
  • 1970-01-01
  • 1970-01-01
  • 2016-05-04
  • 1970-01-01
相关资源
最近更新 更多