我正在尝试使用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
错误吗?
您的command
使用管道|
。它需要一个外壳:
p = subprocess.Popen(command, shell=True)
据我所知[command
本身看起来还不错。
无需使用shell=True
即可通过管道实现此目的。甚至可以通过管道where concern about insecure input is an issue以编程方式完成此操作。在这里,conn_params
是具有PASSWORD
,NAME
(数据库名称),USER
和HOST
键的字典。
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)
以下内容在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 128x128
。 command1
的字符串可以保持不变。
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()
最好以这种方式使用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平台上出现一些路径问题。
[C0很重要,如果您想像在本地shell中执行命令一样执行命令。
希望会帮助您。