Python子进程(shell = True),不适用于postgres命令

时间:2014-01-02 17:52:07

标签: linux postgresql subprocess

使用命令行,我确认以下命令正确执行

echo '\c mydatabase;\i db-reset.sql' | psql -U postgres -h localhost

但是,在Python中,我可以确认以下行绝对没有任何内容,并返回状态代码0。

import subprocess

code = subprocess.call(r"echo '\c mydatabase;\i db-reset.sql' | psql -U postgres -h localhost", shell=True)
assert code == 0 # This comes to true

基本上,为什么使用子进程调用的命令实际上没有做任何事情

2 个答案:

答案 0 :(得分:5)

它可以工作,但你需要更多的反斜杠。 另外,我建议你不要在这里使用shell=True

这就是你做的,但没有shell:

p = subprocess.Popen(['psql', '-U', 'postgres', '-h', 'localhost'], shell=False, stdin=subprocess.PIPE)
p.communicate(r"\c mydatabase;\i db-reset.sql")

答案 1 :(得分:2)

伊戈尔毫无疑问有正确的方法 - 尽管之后关闭会议是个好主意。但是,这里有一个更大的图片问题,那就是你通常不应该调用psql来与Python的进行PostgreSQL通信。

使用the psycopg2 module,它几​​乎无处不在,可以直接与PostgreSQL对话。这将极大地简化您的数据库通信。

对于实际需要psql的情况,如运行脚本,请使用psql -f和数据库参数。在这种情况下,您的命令应该是:

try:
    subprocess.check_call([
        'psql', '-q',
        '-U', 'postgres', 
        '-h', 'localhost',
        '-f', 'db-reset.sql', 
        'mydatabase'
     ])
except subprocess.CalledProcessError, ex:
    print("Failed to invoke psql: {0}".format(ex))

...甚至更好,如果您使用的是足够新的Python版本,请使用check_output,这样您也可以捕获错误输出。请注意-q(安静模式)标志。

(请注意,当你在像Windows这样没有合理subprocess变体系统调用或等价物的平台上运行时,execv会自行转义。所以你不需要关心痛苦的外壳逃避怪癖。)