如何使用子进程Popen?

时间:2014-02-28 09:07:05

标签: python postgresql subprocess popen raster

我正在尝试使用Popen执行命令。

该命令使用一些PostGIS / Postgresql实用程序将光栅文件上载到数据库,并在从命令行执行时工作。它使用unix样式的管道链接2个命令,如下所示:

"C:\\Program Files\\PostgreSQL\\9.2\\bin\\raster2pgsql.exe" -d -I -C -e -Y -F -t 128x128 "C:\\temp\\SampleDTM\\SampleDTM.tif" test | "C:\\Program Files\\PostgreSQL\\9.2\\bin\\psql.exe" -h localhost -p 5432 -d adr_hazard -U postgres

在Python中使用时,我将其设为包含'代码的字符串:

command = '"C:\\Program Files\\PostgreSQL\\9.2\\bin\\raster2pgsql.exe" -d -I -C -e -Y -F -t 128x128 "C:\\temp\\SampleDTM\\SampleDTM.tif" test | "C:\\Program Files\\PostgreSQL\\9.2\\bin\\psql.exe" -h localhost -p 5432 -d adr_hazard -U postgres'

尝试执行它会导致错误:

p = subprocess.Popen(command)

ERROR: Unable to read raster file: test

错误似乎没有正确解析命令(它将错误的参数解释为光栅文件)

我使用Popen错了吗?

5 个答案:

答案 0 :(得分:3)

您的command使用了管道|。它需要一个shell:

p = subprocess.Popen(command, shell=True)

就我所知,command本身看起来还不错。

答案 1 :(得分:1)

没有必要使用shell=True来实现管道。这可以使用管道where concern about insecure input is an issue以编程方式完成。在此处,conn_params是包含PASSWORDNAME(数据库名称),USERHOST键的字典。

raster2pgsql_ps = subprocess.Popen([
    'raster2pgsql', '-d', '-I', '-C', '-e', '-Y', '-F', '-t', '128x128',
    'C:\\temp\\SampleDTM\\SampleDTM.tif',
    'test'
], stdout=subprocess.PIPE)

# Connection made using conninfo parameters
# http://www.postgresql.org/docs/9.0/static/libpq-connect.html
psql_ps = subprocess.check_output([
    'psql',
    'password={PASSWORD} dbname={NAME} user={USER} host={HOST}'.format(**conn_params),
], stdin=raster2pgsql_ps.stdout)

答案 2 :(得分:0)

以下内容在Windows上对我有用,同时避免了shell=True

一个人可以利用Python的fstring formatting来确保命令在Windows中可以使用。

请注意,我使用了shp2pgsql,但这对于raster2pgsql来说应该是非常相似的过程。

shp2pgsql的参数:srid是形状文件的坐标系,filename是要导入的形状文件的路径,tablename是名称你想给你的桌子。

import os
import subprocess

shp2pgsql_binary = os.path.join(pgsql_dir, "bin", "shp2pgsql")
psql_binary = os.path.join(pgsql_dir, "bin", "psql")

command0 = f'\"{shp2pgsql_binary}\" -s {srid} \"{filename}\" {tablename}'
command1 = f'\"{psql_binary}\" \"dbname={databasename} user={username} password={password} host={hostname}\"'

try:
    shp2pgsql_ps = subprocess.Popen(command0, stdout=subprocess.PIPE)
    psql_ps = subprocess.check_output(command1, stdin=shp2pgsql_ps.stdout)
except:
    sys.stderr.write("An error occurred while importing data into the database, you might want to \
                        check the SQL command below:")
    sys.stderr.write(command)
    raise

要适应raster2pgsql,只需修改command0中的字符串,例如-s {srid}成为-d -I -C -e -Y -F -t 128x128command1的字符串可以保持不变。

答案 3 :(得分:-1)

  PIPE = subprocess.PIPE
  pd = subprocess.Popen(['"C:\\Program Files\\PostgreSQL\\9.2\\bin\\raster2pgsql.exe", '-d', '-I', '-C', '-e', '-Y', '-F', '-t', '128x128', "C:\\temp\\SampleDTM\\SampleDTM.tif", 'test'],
    stdout=PIPE, stderr=PIPE)
  stdout, stderr = pd.communicate()

答案 4 :(得分:-2)

以这种方式使用subprocess.Popen会更好:

proc = subprocess.Popen(['"C:\\Program Files\\PostgreSQL\\9.2\\bin\\raster2pgsql.exe"', '-d', '-I', '-C', '-e', '-Y', '-F', '-t', '128x128', '"C:\\temp\\SampleDTM\\SampleDTM.tif"', 'test', '|', '"C:\\Program Files\\PostgreSQL\\9.2\\bin\\psql.exe"', '-h', 'localhost', '-p', '5432', '-d', 'adr_hazard', '-U', 'postgres'], shell = True, stdout = subprocess.pipe, stderr = subprocess.STDOUT)
proc.wait()
result = proc.stdout.readlines()#if you want to process the result of your command
proc.kill()

B.T.W,首先格式化路径是好的,使用:

path = os.path.normalpath("C:\\Program Files\\PostgreSQL\\9.2\\bin\\raster2pgsql.exe")

这将避免不同OS平台的一些路径问题。

如果您想执行命令就像在本地shell中执行命令一样,shell = True很重要。

希望能帮到你。