Str*_*rae 5 python mysql subprocess
我在尝试构建简单的备份/升级数据库脚本时遇到问题。
错误出现在使用子进程的 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)
Run Code Online (Sandbox Code Playgroud)
在此之前,我将sys.stdout和重定向sys.stderr到文件,以便拥有一个日志系统。
在这些日志中,我发现错误:
[mysqldump --user=xxxxxx --password=yyyyyyyy 数据库名称 | 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]
Run Code Online (Sandbox Code Playgroud)
我已经编辑了我的脚本:
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()
Run Code Online (Sandbox Code Playgroud)
现在命令变量只是为了方便在日志中使用。
这将继续下一步,但它会在>流中停止,并出现以下错误:
[Error]: gzip: >: No such file or directory
gzip: /path/to/backups/dir/natabase_name.sql.gz: No such file or directory
Run Code Online (Sandbox Code Playgroud)
显然,如果我在终端中尝试该命令,它就会起作用。
给定路径、用户、密码和数据库名后,以下内容就像一个魅力:
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)
Run Code Online (Sandbox Code Playgroud)
使用fas stdout 参数subprocess.Popen()也可以,但不会压缩数据。在Python 2.7之前,该with语句不起作用,因此使用f=gzip.open(..)and 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))
Run Code Online (Sandbox Code Playgroud)
我不确定管道将如何被解释。如果这是一个问题,您可以通过编程方式创建一个管道。
\n\n来自:\n http://docs.python.org/library/subprocess.html#replacing-shell-pipeline
\n\np1 = Popen(["dmesg"], stdout=PIPE)\np2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)\noutput = p2.communicate()[0]\nRun Code Online (Sandbox Code Playgroud)\n\n编辑
\n\n至于文件重定向,您可以将 stdout 定向到文件。
\n\n\n\n\nstdin、stdout 和 stderr 分别指定\n 执行的程序\xe2\x80\x99 标准输入、\n 标准输出和标准错误\n 文件句柄。有效值为 PIPE、现有文件描述符(正整数)、现有文件对象和 None。
\n
例子:
\n\nout_file = open(out_filename, "wb")\ngzip_proc = subprocess.Popen("gzip", stdout=out_file)\ngzip_proc.communicate()\nRun Code Online (Sandbox Code Playgroud)\n\n或者如果您采纳 Alex 的建议并使用 Python 的标准库gzip模块,您可以执行以下操作:
\n\nimport gzip\nimport subprocess\n\n...\n#out_filename = path to gzip file\n\ncmdL1 = ["mysqldump", "--user=" + db_user, "--password=" + db_pass, domaindb]\np1 = subprocess.Popen(cmdL1, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\ndump_output = p1.communicate()[0]\n\nf = gzip.open(out_filename, "wb")\nf.write(dump_output)\nf.close()\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
11023 次 |
| 最近记录: |