web-dev-qa-db-ja.com

stdinから直接.tar.gzファイルを作成することは可能ですか?または、すでにgzipされたファイルを一緒にtarする必要があります

タイトルの謎めいた質問を明確にするために必要なことを正確に説明します。私は現在、次のようなものですべてのデータベースのMySQLバックアップをスケジュールしています。

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

これは問題ありませんが、ダンプされたデータを確認したり、単一のデータベースを復元したりするのが簡単になるので、単一のデータベースごとに個別のファイルを作成したいと思っています。

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

各単一バックアップのすべてのダンプを単一の.tarファイルに保存します。つまり、すべてのダンプされたデータベースが含まれるmysql-backup.tar.gzです。私は単に.sqlファイルを圧縮せずにtar -cz *.sqlのままにしておくことができることを知っていますが、1)大きなファイルを一時的に保存する必要がない方法を探しています。実際、現在のスクリプトでは、mysqldumpgzipにパイプ処理されるため、大きなファイルは作成されません。

2)stdinから.tar.gzを作成できる同様の方法はありますか?

tar -c *.sql.gztar -cz *.sqlと同等ですか?

7
lorenzo-s

私はいくつかのpython必要なことをするために一緒に石畳を作りました。それはpythonのtarfileライブラリを使用してstdinをtarファイルに追加し、次にtarをシークして書き換えますeofで適切なサイズのヘッダー。使用法は次のようになります。

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

これがtarappend 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)
5
meuh

簡単ではありません。 tarは、ファイルのコンテンツだけでなく、ファイルのメタデータ(名前、タイムスタンプ、権限、所有者など)も記録します。その情報はどこかから来る必要があり、パイプの中に存在することはありません。

データベースダンプをファイル(おそらく問題のデータベースの名前が付けられている)にgzip圧縮し、そのファイルをtarアーカイブに追加してから、次のデータベースに進む前にファイルを削除できます。その結果、.gz.tarファイルが生成されます。これは珍しいことですが、まったく問題がなく、おそらくデータベース全体のダンプをgzip圧縮するよりもはるかに多くのディスクを使用しません(圧縮できないため、圧縮効率が少し低くなります)データベースの境界を越えて共有)。

4
Calle Dybedahl

いいえ、そしてその機能がとても恋しいです Ask Ubuntuでの私の質問

アーカイブするファイルがファイルシステムメタデータが関連付けられていないrawファイルである場合、tarには、内部ディレクトリ/ファイルツリーを構築するために必要なファイル名もパスもありません(控えめに言っても)。

ファイルの圧縮/解凍/アーカイブ専用のライブラリを備えたPerlで何かができると思います:この答えを最大限に活用できるかどうかを確認してください: Ask Ubuntuの関連する答え

1
kos

tardy tarポストプロセッサーの使用を検討できます。

ただし、tarの使用に疑問を呈し、アイテムをアーカイブする他の方法を検討する場合があります。特に rsync および afio を検討してください

mysqldump--export-allオプションを理解することに注意してください( this を参照)。パイプラインを使用して、境界などを理解するスクリプトに組み込むことができます。

これが私がやったことです、tmpファイルを作成します(そして後でそれを削除します)

temp=$(mktemp)
trap "rm $temp" EXIT
echo 'blabla' >$temp
tar czf - $temp
0
phil294