簡體   English   中英

Python子進程,mysqldump和管道

[英]Python subprocess, mysqldump and pipes

我在嘗試構建一個簡單的備份/升級數據庫腳本時遇到了問題。

錯誤發生在使用子進程的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

顯然,如果我在終端中嘗試命令,它可以工作。

我不確定如何解釋管道。 如果這是一個問題,您可以以編程方式創建一個pipelilne。

來自: 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()

使用path,user,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作為stdout參數也可以工作但不壓縮數據。 在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)) 

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

管道(和重定向)被這樣識別並由shell調度,並且,默認情況下(在Unix上), subprocess進程避免使用shell(它更慢並且控制較少) - 你需要明確強制shell進入控制,如果管道或重定向是你絕對必須擁有的。

通常情況下,人們試圖通過在Python中盡可能多地執行操作來避免管道(因此避免shell=True和出席問題)(例如,在您的情況下,使用Python標准庫的gzip模塊)。 當然,對於這個必須小心地將stdout(將要進一步處理)與stderr分開,作為兩個單獨的管道。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM