Saya akan memberi tahu Anda apa yang saya butuhkan untuk mengklarifikasi pertanyaan samar dalam judul. Saat ini saya membuat cadangan MySQL terjadwal dari semua database saya dengan sesuatu seperti:
mysqldump ... | gzip -c > mysql-backup.gz
Tidak apa-apa, tapi saya ingin membuat file terpisah untuk setiap database tunggal, karena itu akan memudahkan untuk melihat data yang dibuang atau memulihkan satu database:
for db in $dbs; do mysqldump ... $db | gzip -c > mysql-backup-$db.gz; done
Saya ingin menyimpan semua dump untuk setiap cadangan dalam satu .tar
file, yaitu mysql-backup.tar.gz
dengan semua database yang dibuang di dalamnya. Saya tahu saya bisa meninggalkan .sql
file tidak terkompresi dan kemudian tar -cz *.sql
, tapi 1) Saya mencari cara yang tidak perlu menyimpan file besar untuk sementara . Dalam skrip saya saat ini, sebenarnya, mysqldump
disalurkan ke gzip
, jadi tidak ada file besar yang dibuat.
2) Apakah ada cara serupa untuk membuat .tar.gz
dari stdin ?
3) Apakah tar -c *.sql.gz
setara dengan tar -cz *.sql
?
Jawaban yang Diterima:
Saya membuat beberapa python untuk melakukan apa yang Anda inginkan. Itu menggunakan tarfile python library untuk menambahkan stdin ke file tar, dan kemudian hanya mencari kembali di tar untuk menulis ulang header dengan ukuran yang tepat di eof. Penggunaannya adalah:
rm -f mytar
for db in $dbs
do mysqldump ... $db | gzip -c |
tarappend -t mytar -f mysql-backup-$db.gz
done
tar tvf mytar
Ini tarappend
skrip python:
#!/usr/bin/python
# concat stdin to end of tar file, with given name. meuh on stackexchange
# $Id: tarappend,v 1.3 2015/07/08 11:31:18 meuh $
import sys, os, tarfile, time, copy
from optparse import OptionParser
try:
import grp, pwd
except ImportError:
grp = pwd = None
usage = """%prog: ... | %prog -t tarfile -f filename
Appends stdin to tarfile under the given arbitrary filename.
tarfile is created if it does not exist.
"""
def doargs():
parser = OptionParser(usage=usage)
parser.add_option("-f", "--filename", help="filename to use")
parser.add_option("-t", "--tarfile", help="existing tar archive")
(options, args) = parser.parse_args()
if options.filename is None or options.tarfile is None:
parser.error("need filename and tarfile")
if len(args):
parser.error("unknown args: "+" ".join(args))
return options
def copygetlen(fsrc, fdst):
"""copy data from file-like object fsrc to file-like object fdst. return len"""
totlen = 0
while 1:
buf = fsrc.read(16*1024)
if not buf:
return totlen
fdst.write(buf)
totlen += len(buf)
class TarFileStdin(tarfile.TarFile):
def addstdin(self, tarinfo, fileobj):
"""Add stdin to archive. based on addfile() """
self._check("aw")
tarinfo = copy.copy(tarinfo)
buf = tarinfo.tobuf(self.format, self.encoding, self.errors)
bufoffset = self.offset
self.fileobj.write(buf)
self.offset += len(buf)
tarinfo.size = copygetlen(fileobj, self.fileobj)
blocks, remainder = divmod(tarinfo.size, tarfile.BLOCKSIZE)
if remainder > 0:
self.fileobj.write(tarfile.NUL * (tarfile.BLOCKSIZE - remainder))
blocks += 1
self.offset += blocks * tarfile.BLOCKSIZE
# rewrite header with correct size
buf = tarinfo.tobuf(self.format, self.encoding, self.errors)
self.fileobj.seek(bufoffset)
self.fileobj.write(buf)
self.fileobj.seek(self.offset)
self.members.append(tarinfo)
class TarInfoStdin(tarfile.TarInfo):
def __init__(self, name):
if len(name)>100:
raise ValueError(name+": filename too long")
if name.endswith("/"):
raise ValueError(name+": is a directory name")
tarfile.TarInfo.__init__(self, name)
self.size = 99
self.uid = os.getuid()
self.gid = os.getgid()
self.mtime = time.time()
if pwd:
self.uname = pwd.getpwuid(self.uid)[0]
self.gname = grp.getgrgid(self.gid)[0]
def run(tarfilename, newfilename):
tar = TarFileStdin.open(tarfilename, 'a')
tarinfo = TarInfoStdin(newfilename)
tar.addstdin(tarinfo, sys.stdin)
tar.close()
if __name__ == '__main__':
options = doargs()
run(options.tarfile, options.filename)