如何在Python中使用正确的子进程Pclose?

时间:2014-04-01 09:06:39

标签: postgresql python-3.x subprocess popen

我在Python 3.3中编写了一个脚本,它对PostgreSQL数据库进行查询。我正在使用子流程 Popen ,它可以工作,但我很新做这个,我想我不知道它是如何实际工作的。我的问题是:

做完Popen后我必须关闭任何东西吗?

我阅读了一些说是的论坛和教程,但是当我对查询结果执行kill或其他命令时,很明显,我会收到类似这样的消息:

  

'list'对象没有属性'kill'

我试过信号和killpg,任何想法?这是我的两个代码查询:

database_list = subprocess.Popen('echo "select datname from pg_database" '
                                 '| psql -t -U %s -h %s template1' %
                                 (bkp_vars['user'], bkp_vars['host']),
                                 shell=True,
                                 stdout=subprocess.PIPE).stdout.readlines()

update_result = subprocess.Popen('echo "UPDATE pg_database SET datallowconn = TRUE WHERE   datname = \'template0\'" '
                                    '| psql -t -U %s -h %s template1' %
                                    (bkp_vars['user'],bkp_vars['host']), shell=True,
                                    stdout=subprocess.PIPE).stdout.readlines()

提前谢谢!

1 个答案:

答案 0 :(得分:4)

首先,对于psycopg2(PostgreSQL的Python接口)而言,这比使用subprocesspsql要好得多。

此外,如果您正在进行备份,则应该使用pg_dumppg_restore,而不是弄乱psql

如何获取数据库列表

import psycopg2

# Replace connection parameters with those for your DB; see the psycopg2 docs
conn = psycopg2.connect("dbname=postgres user=myusername password=whatever")

curs = conn.cursor()
curs.execute("select datname from pg_database;")
dbs = curs.fetchall()

print dbs

更好地使用subprocess

如果你必须使用psql,那么你需要意识到Popen会返回subprocess.Popen object

这些表示子进程。您可以将它们用于wait for the child process to finish,以读取子进程输出等。

大多数情况下,您将使用诸如subprocess.check_callsubprocess.check_output之类的包装器接口,这样可以自动执行此操作并使其更容易换取灵活性降低。在您的情况下,我认为您需要subprocess.check_output

subproces可用于将stdin写入对象,方法是传递包含所需stdin的临时文件,或者直接写入Popen构造函数返回的stdin文件句柄。您不应该像echo stdin那样通过subprocess模块打开进程。

如果您必须使用psql执行此操作,则需要更多类似的内容:

import subprocess

username = "postgres"
dbname = "postgres"

p = subprocess.Popen(
  args = ['psql', '-qAt', '-0', '-U', username, dbname],
  stdin = subprocess.PIPE,
  stdout = subprocess.PIPE
)
p.stdin.write("SELECT datname FROM pg_database;");
p.stdin.close()
dbs = p.stdout.read().split('\0')
print dbs
p.wait() 

请注意使用空字节作为记录分隔符,因此可以正确解析其中包含换行符的数据库名称。