GNU/Linux >> Linux Esercitazione >  >> Linux

È possibile creare un file .tar.gz direttamente da Stdin? Oppure, devo eseguire il tar insieme di file già compressi?

Ti dirò esattamente di cosa ho bisogno per chiarire la domanda criptica nel titolo. Attualmente sto eseguendo backup MySQL programmati di tutti i miei database con qualcosa del tipo:

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

Questo va bene, ma sono disposto a creare un file separato per ogni singolo database, poiché ciò renderà più semplice dare un'occhiata ai dati scaricati o ripristinare un singolo database:

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

Vorrei archiviare tutti i dump di ogni singolo backup in un unico .tar file, ovvero mysql-backup.tar.gz con tutti i database scaricati all'interno. So che posso semplicemente lasciare .sql file non compressi e quindi tar -cz *.sql , ma 1) Sto cercando un modo che non necessiti di archiviare temporaneamente file di grandi dimensioni . Nel mio script attuale, infatti, mysqldump viene inviato tramite pipe a gzip , quindi non viene creato alcun file di grandi dimensioni.

2) Esiste un modo simile in cui posso creare .tar.gz da stdin ?

3) È tar -c *.sql.gz equivalente a tar -cz *.sql ?

Risposta accettata:

Ho messo insieme del pitone per fare quello che vuoi. Utilizza il file tar di Python library per aggiungere stdin a un file tar, quindi cerca semplicemente di tornare nel tar per riscrivere l'intestazione con la giusta dimensione in eof. L'utilizzo sarebbe:

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

Ecco il tarappend script 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)

Linux
  1. Come risolvere:stdin:non in formato gzip

  2. È possibile scaricare file estremamente grandi in modo intelligente o in parti tramite Ssh da Linux a Windows?

  3. Ho bisogno di creare un gruppo di utenti?

  4. Come distinguere il binario dai file di testo in Linux

  5. Come gzippare più file in un unico file gz?

Come estrarre o decomprimere i file tar.gz dalla riga di comando di Linux

Come eseguire il tar di tipi di file specifici (estensioni) in una directory

Comando tar di Linux per comprimere ed estrarre file

Comprimi i file durante la lettura dei dati da STDIN

Hai bisogno di un buon editor esadecimale per Linux

Come creare un file tar locale di una directory remota