Có thể tạo tệp .tar.gz trực tiếp từ stdin không? Hoặc, tôi cần tar các tập tin đã được nén với nhau


7

Tôi sẽ nói với bạn chính xác những gì tôi cần để làm rõ câu hỏi khó hiểu trong tiêu đề. Tôi hiện đang thực hiện sao lưu MySQL theo lịch trình của tất cả các cơ sở dữ liệu của mình với nội dung như:

mysqldump ... | gzip -c > mysql-backup.gz

Điều này không sao, nhưng tôi sẵn sàng tạo một tệp riêng cho từng cơ sở dữ liệu, vì điều đó sẽ giúp dễ dàng hơn khi xem dữ liệu bị đổ hoặc khôi phục một cơ sở dữ liệu:

for db in $dbs; do mysqldump ... $db | gzip -c > mysql-backup-$db.gz; done

Tôi muốn lưu trữ tất cả các bãi chứa cho mỗi bản sao lưu trong một .tartệp duy nhất , tức là mysql-backup.tar.gzvới tất cả các cơ sở dữ liệu bị đổ bên trong. Tôi biết rằng tôi chỉ có thể để .sqlcác tệp không bị nén và sau đó tar -cz *.sql, nhưng 1) Tôi đang tìm kiếm một cách không cần thiết để lưu trữ tạm thời các tệp lớn . Trong kịch bản hiện tại của tôi, trên thực tế, mysqldumpđược dẫn vào gzip, vì vậy không có tệp lớn nào được tạo.

2) Có cách nào tương tự để tôi có thể tạo .tar.gztừ stdin không?

3) Có tar -c *.sql.gzeqivalent tới tar -cz *.sql?



3
@jhilmer Các câu hỏi được liên kết là về việc lấy tên tệp từ stdin, không phải dữ liệu thực tế.
lorenzo-s

1
Được tar -c *.sql.gzeqivalent tới tar -cz *.sql? - Không, cái sau hiệu quả hơn một chút, nhưng điều đó tạo ra nhiều sự khác biệt cho nhiều tệp nhỏ hơn là một vài tệp lớn.
lcd047

Câu trả lời:


5

Tôi cùng nhau bò một số con trăn để làm những gì bạn muốn. Nó sử dụng thư viện tarfile của python để nối stdin vào một tệp tar, và sau đó chỉ cần tìm lại trong tar để viết lại tiêu đề với kích thước phù hợp tại eof. Việc sử dụng sẽ là:

rm -f mytar
for db in $dbs
do mysqldump ... $db | gzip -c |
   tarappend -t mytar -f mysql-backup-$db.gz
done
tar tvf mytar

Đây là tarappendkịch bản 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)

4

Không dễ dàng. targhi lại không chỉ nội dung tệp, mà còn siêu dữ liệu tệp (tên, dấu thời gian, quyền, chủ sở hữu và như vậy). Thông tin đó phải đến từ một nơi nào đó và nó sẽ không ở đó trong một đường ống.

Bạn có thể gzip cơ sở dữ liệu của mình vào một tệp (có thể được đặt tên cho cơ sở dữ liệu được đề cập), nối tệp vào tệp lưu trữ tar và sau đó xóa tệp trước khi tiếp tục cơ sở dữ liệu tiếp theo. Điều đó sẽ dẫn đến một tệp .gz.tar, điều này không bình thường nhưng không có vấn đề gì, và có lẽ không sử dụng nhiều đĩa hơn so với việc kết xuất toàn bộ cơ sở dữ liệu (nó sẽ được nén ít hiệu quả hơn vì không thể chia sẻ qua biên giới cơ sở dữ liệu).


1

Không, và tôi nhớ tính năng đó rất nhiều: câu hỏi của tôi về Hỏi Ubuntu .

Nếu tệp được lưu trữ là một tệp thô không có siêu dữ liệu hệ thống tệp được liên kết với nó, tarthì không có tên tệp cũng như đường dẫn cần thiết để xây dựng cây thư mục / tệp nội bộ (để nói là ít nhất).

Tôi nghĩ rằng một cái gì đó có thể được thực hiện trong Perl, nơi có một số thư viện dành riêng cho việc nén / giải nén / lưu trữ các tệp: xem bạn có thể tận dụng tối đa câu trả lời này không: một câu trả lời liên quan trên Hỏi Ubuntu .


0

Bạn có thể xem xét sử dụng trễ tar hậu xử lý.

Tuy nhiên, bạn có thể đặt câu hỏi về việc sử dụng tar và xem xét một số cách khác để lưu trữ những thứ của bạn. Đặc biệt xem xét rsyncafio

Lưu ý rằng mysqldump hiểu các --export-alltùy chọn (xem điều này ). Bạn có thể chuyển nó thành một số kịch bản hiểu ranh giới, v.v ...


0

đây là những gì tôi đã làm, tạo một tệp tmp (và xóa nó sau đó)

temp=$(mktemp)
trap "rm $temp" EXIT
echo 'blabla' >$temp
tar czf - $temp
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.