GNU/Linux >> Tutoriels Linux >  >> Linux

Est-il possible de créer un fichier .tar.gz directement à partir de Stdin ? Ou, j'ai besoin de tarer ensemble des fichiers déjà compressés ?

Je vais vous dire exactement ce dont j'ai besoin pour clarifier la question énigmatique dans le titre. Je fais actuellement des sauvegardes MySQL planifiées de toutes mes bases de données avec quelque chose comme :

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

C'est correct, mais je suis prêt à créer un fichier séparé pour chaque base de données, car cela facilitera l'examen des données vidées ou la restauration d'une seule base de données :

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

J'aimerais stocker tous les vidages pour chaque sauvegarde dans un seul .tar fichier, c'est-à-dire mysql-backup.tar.gz avec toutes les bases de données sous-évaluées à l'intérieur. Je sais que je peux simplement laisser .sql fichiers non compressés puis tar -cz *.sql , mais 1) Je cherche un moyen qui n'a pas besoin de stocker temporairement de gros fichiers . Dans mon script actuel, en fait, mysqldump est redirigé vers gzip , donc aucun gros fichier n'est créé.

2) Existe-t-il une manière similaire de créer .tar.gz depuis stdin ?

3) Est-ce que tar -c *.sql.gz équivalent à tar -cz *.sql ?

Réponse acceptée :

J'ai bricolé du python pour faire ce que tu veux. Il utilise le fichier tar de python bibliothèque pour ajouter stdin à un fichier tar, puis revient simplement dans le tar pour réécrire l'en-tête avec la bonne taille à eof. L'utilisation serait :

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

Voici le 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. Comment tar (compresser) des fichiers, en excluant certains fichiers ou répertoires

  2. Scripts auto-extractibles :Tar -xo et Dd ?

  3. J'ai besoin de créer un lot d'utilisateurs ?

  4. Compresser les fichiers lors de la lecture des données de STDIN

  5. Comment compresser plusieurs fichiers dans un seul fichier gz?

Comment extraire ou décompresser des fichiers tar.gz à partir de la ligne de commande Linux

Comment tarer des types de fichiers spécifiques (extensions) dans un répertoire

Commande Linux tar pour compresser et extraire des fichiers

extraire un seul fichier d'un énorme fichier tgz

Comment créer un fichier tar local d'un répertoire distant

Obtenir la taille totale des fichiers à partir d'un fichier contenant une liste de fichiers