Remova com eficiência arquivos do .tgz grande

14

Suponha que eu tenha um arquivo compactado com gzip tar-ball compressedArchive.tgz (+100 arquivos, totalizando + 5gb).

Qual seria a maneira mais rápida de remover todas as entradas correspondentes a um determinado padrão de nome de arquivo, por exemplo, prefixo * .jpg e, em seguida, armazenar os restos em uma bola de gzip: ed novamente?

Substituir o arquivo antigo ou criar um novo não é importante, o que for mais rápido.

Aksel Willgert
fonte

Respostas:

14

Com o GNU tar, você pode fazer:

pigz -d < file.tgz |
  tar --delete --wildcards -f - '*/prefix*.jpg' |
  pigz > newfile.tgz

Com bsdtar:

pigz -d < file.tgz |
  bsdtar -cf - --exclude='*/prefix*.jpg' @- |
  pigz > newfile.tgz

( pigzsendo a versão multithread do gzip).

Você pode sobrescrever o arquivo sobre si mesmo, como:

{ pigz -d < file.tgz |
    tar --delete --wildcards -f - '*/prefix*.jpg' |
    pigz &&
    perl -e 'truncate STDOUT, tell STDOUT'
} 1<> file.tgz

Mas isso é bastante arriscado, especialmente se o resultado acabar sendo menos compactado que o arquivo original (nesse caso, o segundo pigzpoderá acabar substituindo as áreas do arquivo que o primeiro ainda não leu).

Stéphane Chazelas
fonte
obrigado pela resposta, votou. executará benchmark na próxima semana para ver qual é o melhor para meu arquivo e sistema e aceite isso.
Aksel Willgert
8

Não descarte da maneira mais fácil: ela pode ser rápida o suficiente para o seu propósito. Com o avfs para acessar o arquivo morto como um diretório:

cd ~/.avfs/path/to/original.tar.gz\#
pax -w -s '/^.*\.jpg$//' | gzip >/path/to/filtered.tar.gz        # POSIX
tar -czf /path/to/filtered.tar.gz -s '/^.*\.jpg$//' .            # BSD
tar -czf /path/to/filtered.tar.gz --transform '/^.*\.jpg$//' .   # GNU

Com ferramentas mais primitivas, primeiro extraia os arquivos excluindo os .jpgarquivos e crie um novo arquivo morto.

mkdir tmpdir && cd tmpdir
<original.tar.gz gzip -d | pax -r -pe -s '/^.*\.jpg$//'
pax -w . | gzip >filtered.tar.gz
cd .. && rm -rf tmpdir

Se o seu alcatrão tem --exclude:

mkdir tmpdir && cd tmpdir
tar -xzf original.tar.gz --exclude='*.jpg'
tar -czf filtered.tar.gz .
cd .. && rm -rf tmpdir

No entanto, isso pode alterar a propriedade e os modos do arquivo, se você não executá-lo como root. Para obter melhores resultados, use um diretório temporário em um sistema de arquivos rápido - tmpfs, se você tiver um que seja grande o suficiente.

O suporte aos arquivadores para atuar como passagem (isto é, ler um arquivo e escrever um arquivo) tende a ser limitado. O tar GNU pode excluir membros de um arquivo com a --deleteopção de operação (“A --deleteopção foi relatada para funcionar corretamente quando taratua como um filtro de stdinpara stdout.”), E essa é provavelmente a sua melhor opção.

Você pode criar poderosos filtros de arquivamento em algumas linhas do Python. Sua tarfilebiblioteca pode ler e gravar a partir de fluxos não procuráveis, e você pode usar código arbitrário no Python para filtrar, renomear, modificar…

#!/usr/bin/python
import re, sys, tarfile
source = tarfile.open(fileobj=sys.stdin, mode='r|*')
dest = tarfile.open(fileobj=sys.stdout, mode='w|gz')
for member in source:
    if not (member.isreg() and re.match(r'.*\.jpg\Z', member.name)):
        sys.stderr.write(member.name + '\n')
        dest.addfile(member, source.extractfile(member))
dest.close()
Gilles 'SO- parar de ser mau'
fonte
Ele também manipularia uid / usernames se executado como root, a menos que seja feito em uma máquina que tenha o mesmo mapeamento de nome de usuário uid <=> como aquele em que o arquivo tar foi criado inicialmente. ACLs, atributos estendidos também podem ser afetados. Com tar, você pode querer adicionar a popção.
Stéphane Chazelas 19/03/19
2

Com o alcatrão que vem no Mac OSX, você pode fazer o seguinte:

tar -czf b.tgz --exclude '*.jpg' @a.tgz
mv b.tgz a.tgz
Jake
fonte
1

Para fazer isso, você provavelmente precisará extrair todo o conteúdo do arquivo .tgz em um diretório local e, em seguida, apagar os arquivos que não deseja e, em seguida, recomprimir o arquivo .tgz.

É longo e você precisa de espaço livre em disco suficiente, mas, pelo que sei, não há outra maneira de fazê-lo.

Dado que você já possui um caminho como /tmpdir/withalotofspaceesse e possui espaço livre suficiente (verifique usando df -h /tmpdir/withalotofspace), você pode fazer algo assim:

$ cd /tmpdir/withalotofspace
$ tar -xvfz /path/to/compressedArchive.tgz
$ find /tmpdir/withalotofspace/ -type f -iname '*.jpg' -delete
$ tar -cvzf /path/to/purgedcompressedArchive.tgz .
DavAlPi
fonte
Como as outras respostas mostrar, através de tubulação, não há necessidade de armazenar dados não comprimidos no disco em qualquer ponto
Tobias KIENZLER
0

Gosto da resposta do @Gilles, exceto que pode ser ainda mais simplificada. Após descompactar, por exemplo, gunzip foo.tgzo arquivo será foo.tare os arquivos poderão ser removidos com tar -f foo.tar --delete file|directory. Abaixo está um exemplo de remoção de um diretório de um arquivo tar.

    phablet@ubuntu-phablet:~/Downloads$ tar -cvf moo.tar moo1/
    moo1/
    moo1/moo2/
    moo1/moo2/moo3/
    moo1/moo2/moo3/moo4/
    moo1/moo2/moo3/moo4/moo5/
    phablet@ubuntu-phablet:~/Downloads$ tar -tf moo.tar 
    moo1/
    moo1/moo2/
    moo1/moo2/moo3/
    moo1/moo2/moo3/moo4/
    moo1/moo2/moo3/moo4/moo5/
    phablet@ubuntu-phablet:~/Downloads$ tar -f moo.tar --delete "moo1/moo2/moo3"
    phablet@ubuntu-phablet:~/Downloads$ tar -tf moo.tar 
    moo1/
    moo1/moo2/

Tipos de arquivos específicos podem ser encontrados com tar -tf foo.tar|egrep -i '.jpg$'.

Funmungus
fonte