【问题标题】:Python subprocess, mysqldump and pipesPython 子进程、mysqldump 和管道
【发布时间】:2011-04-05 18:47:23
【问题描述】:

我在尝试构建简单的备份/升级数据库脚本时遇到问题。

错误在使用子进程的mysqldump调用中:

cmdL = ["mysqldump", "--user=" + db_user, "--password=" + db_pass, domaindb + "|", "gzip", ">", databases_path + "/" + domaindb + ".sql.gz"]
print "%s: backup database %s \n\t[%s]" % (domain, domaindb, ' '.join(cmdL))
total_log.write("%s: backup database %s \n\t[%s] \n" % (domain, domaindb, ' '.join(cmdL)))
p = subprocess.Popen(cmdL, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

在此之前,我将sys.stdoutsys.stderr 重定向到文件,以便拥有一个日志系统。

在那些日志中,我发现了错误:

[mysqldump --user=xxxxxx --password=yyyyyyyy database_name | gzip > /home/drush-backup/2010-08-30.15.37/db/database_name.sql] [错误]:mysqldump:找不到表:“|”

似乎| 字符被视为 mysqldump 参数,而不是管道。

查看python子进程文档,这是正常的,但是我怎样才能获得我需要的东西(调用命令mysqldump --user=xxxxxx --password=yyyyyyyy database_name | gzip > /home/drush-backup/2010-08-30.15.37/db/database_name.sql)?

编辑我只是在 python 文档上看到这个例子:

output=`dmesg | grep hda`
==>
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

我已经编辑了我的脚本:

command = ["mysqldump", "--user=" + db_user, "--password=" + db_pass, domaindb, "|", "gzip", ">", databases_path + "/" + domaindb + ".sql.gz"]
cmdL1 = ["mysqldump", "--user=" + db_user, "--password=" + db_pass, domaindb]
cmdL2 = ["gzip", ">", databases_path + "/" + domaindb + ".sql.gz"]

print "%s: backup database %s \n\t[%s]" % (domain, domaindb, ' '.join(command))
total_log.write("%s: backup database %s \n\t[%s] \n" % (domain, domaindb, ' '.join(command)))

p1 = subprocess.Popen(cmdL1, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p2 = subprocess.Popen(cmdL2, stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
cmdError, cmdData = p2.communicate()

现在命令变量只是为了方便日志使用。

下一步,它在> 流中停止,出现以下错误:

[Error]: gzip: >: No such file or directory
gzip: /path/to/backups/dir/natabase_name.sql.gz: No such file or directory

显然,如果我在终端中尝试该命令,它会起作用。

【问题讨论】:

  • 逗号加空格,加号不加。 domaindb 和管道以加号连接。也许这就是问题所在?不知道为什么要用逗号连接字符串,而不是仅仅使用空格并将它们放在相同的引号内。
  • Becose im newbie in python ;) 无论如何,我想我必须使用 +,因为--user= 和 db_user 之间必须没有空格.. 正确的形式应该是 --user=foo,还是我弄错了?

标签: python subprocess mysqldump


【解决方案1】:

我不确定管道将如何被解释。如果这是个问题,您可以通过编程方式创建管道。

来自: http://docs.python.org/library/subprocess.html#replacing-shell-pipeline

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

编辑

至于文件重定向,你可以将stdout指向一个文件..

stdin、stdout 和 stderr 指定 执行程序的标准输入, 标准输出和标准错误 文件句柄,分别。有效的 值是 PIPE,一个现有文件 描述符(一个正整数),一个 现有文件对象和无。

例子:

out_file = open(out_filename, "wb")
gzip_proc = subprocess.Popen("gzip", stdout=out_file)
gzip_proc.communicate()

或者如果你听从 Alex 的建议并使用 Python 的标准库 gzip 模块,你可以这样做:

import gzip
import subprocess

...
#out_filename = path to gzip file

cmdL1 = ["mysqldump", "--user=" + db_user, "--password=" + db_pass, domaindb]
p1 = subprocess.Popen(cmdL1, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
dump_output = p1.communicate()[0]

f = gzip.open(out_filename, "wb")
f.write(dump_output)
f.close()

【讨论】:

  • 我刚刚做了并编辑了我的问题;现在它与> 步骤中断了
【解决方案2】:

在给出路径、用户、pswd 和 dbname 的情况下,以下内容就像一个魅力:

import gzip
from subprocess import Popen, PIPE

cmd = "mysqldump --user={user} --password={pswd} {dbname}".format(**locals())        
p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
with gzip.open(path, "wb") as f:
    f.writelines(p.stdout)

subprocess.Popen() 中使用f 作为标准输出参数也可以,但不会压缩数据。 在 Python 2.7 之前,with 语句不起作用,所以使用f=gzip.open(..)f.close()。可以使用p.stderr.read() 读取错误,因此如果这不是空字符串,则最好引发异常


恢复备份,您可以执行以下操作:
cmd = "mysql --user={user} --password={pswd} {dbname}".format(**locals())
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
with gzip.open(path, "rb") as f:
    p.stdin.write(f.read())
    p.communicate()[0]
    p.stdin.close()
    p_err = p.stderr.read()
if p_err:
    raise Exception('Error restoring database:\n{0}'.format(p_err))

【讨论】:

    【解决方案3】:

    试试subprocess.Popen(' '.join(cmdL), shell=True)

    管道(和重定向)被 shell 识别和调度,默认情况下(在 Unix 上),subprocess 避免使用 shell(它更慢,控制更少) -- 如果管道或重定向是你绝对必须拥有的,你需要显式地强制一个 shell 进行控制。

    通常,通过在 Python 中尽可能多地执行这些操作(例如,在您的情况下,使用 Python 标准库的 gzip 模块)来避免管道(因此避免 shell=True 和随之而来的问题)。当然,为此必须小心地将 stdout(将被进一步处理)与 stderr 分开,作为两个单独的管道。

    【讨论】:

      猜你喜欢
      • 2013-07-27
      • 2015-10-24
      • 1970-01-01
      • 1970-01-01
      • 2017-03-10
      • 2016-06-05
      • 1970-01-01
      • 1970-01-01
      • 2013-03-28
      相关资源
      最近更新 更多