Como posso filtrar o conteúdo de um arquivo tar, produzindo outro arquivo tar no pipe?

12

Considere um único arquivo tar de um sistema externo que contém alguns diretórios com vários atributos que desejo manter, como permissões, mtimes, etc. Como posso facilmente pegar um subconjunto desses arquivos como um usuário comum (não root) ?

Procurando por algo como:

tar -f some.tar.gz --subset subdir/ | ssh remote@system tar xvz

Também é essencial que os atributos principais (propriedade, grupo, modo, mtime) neste arquivo tar sejam mantidos. E quanto a outros atributos em um arquivo tar, como palavras-chave de cabeçalho estendidas ?

Pontos de bônus para uma solução que evita o uso de um diretório temporário, caso esse subdiretório contenha arquivos enormes.

    
por Lekensteyn 22.08.2015 / 21:59

5 respostas

12

O bsdtar (baseado em libarchive) pode filtrar o tar (e alguns outros arquivos) de stdin para stdout. Pode, por exemplo, passar apenas por nomes de arquivos que correspondem a um padrão, e pode fazer s/old/new/ renomeando. Já está empacotado para a maioria das distros, por exemplo, como bsdtar no Ubuntu.

sudo apt-get install bsdtar   # or aptitude, if you have it.

# example from the man page:
bsdtar -c -f new.tar --include='*foo*' @old.tgz
#create new.tar containing only entries from old.tgz containing the string ‘foo’
bsdtar -czf - --include='*foo*' @-  # filter stdin to stdout, with gzip compression of output.

Note que há uma grande variedade de formatos de compressão para entrada / saída, assim você não precisa canalizar manualmente através do gunzip / lz4. Você pode usar - para stdin com a sintaxe @tarfile e / ou - para stdout como normal.

Minha busca também encontrou esta ferramenta de streaming de modificação de tar, que parece querer que você defina as alterações de arquivo que você quer usando o javascript. (Eu acho que a coisa toda está escrita em js).

link

    
por 23.08.2015 / 00:25
4

A maneira mais fácil seria copiar todo o arquivo; Eu presumo que você não queira fazer isso porque é muito grande.

As ferramentas usuais de linha de comando ( tar , pax ) não suportam copiar membros de um arquivo para outro arquivo.

Se você não precisasse preservar a propriedade, sugiro usar sistemas de arquivos FUSE . Você pode usar archivemount para montar um arquivo como um sistema de arquivos; faça isso para o arquivo de origem e execute tar no sistema de arquivos montado.

archivemount some.tar.gz mnt
cd mnt
tar -cz subdir | ssh example.com tar -xz
fusermount -u mnt

Como alternativa, você pode usar o AVFS :

mountavfs
cd ~/.avfs$PWD/some.tar.gz\#
tar -cz subdir | ssh example.com tar -xz

Alternativamente, você pode executar tar no arquivo original e extrair para o computador remoto através do SSHFS .

sshfs example.com: mnt
cd mnt
tar -xf /path/to/some.tar.gz subdir
fusermount -u mnt

No entanto, todos esses métodos são complicados se você precisar preservar a propriedade. Todos eles envolvem a extração para um arquivo na máquina local, portanto, a propriedade desse arquivo terá que ser a propriedade remota pretendida. Isso requer a execução como root e pode não dar o resultado pretendido se os arquivos pertencerem a contas que tenham nomes ou IDs diferentes entre a máquina local e o host remoto.

A biblioteca tarfile do Python fornece uma maneira bastante fácil de manipular os membros do tar, para que você possa embaralhar -los de um arquivo tar para outro. Ele suporta formatos padrão POSIX (ustar, pax), bem como algumas extensões GNU. Aqui está um script Python não testado que lê um arquivo tar (possivelmente compactado com gzip ou bzip2) em sua entrada padrão e grava um arquivo tar compactado com bzip2 em sua saída padrão. Os membros da fonte são copiados se começarem com o argumento passado para o script.

#!/usr/bin/env python2
import sys, tarfile
source = tarfile.open(fileobj=sys.stdin)
destination = tarfile.open(fileobj=sys.stdout, mode='w:bz2')
for info in source:
    if info.name.startswith(sys.argv[1]):
        destination.addfile(info)
destination.close()

Para ser chamado como

tar_filter <some.tar.gz subdir/ | ssh example.com tar -xj
    
por 22.08.2015 / 23:51
0

Uma abordagem alternativa sem privilégios é usar o programa fakeroot para fingir que você tem permissão para alterar a propriedade. Enquanto outros atributos tar são perdidos, ele mantém o modo, mtime e uid / gid. Estes comandos criam um diretório temporário, extraem um subconjunto dos arquivos e finalmente criam um novo arquivo:

mkdir tmp
<some.tar.gz \
fakeroot -- sh -c 'cd tmp && tar -xzf- subdir/ && tar -czf- subdir' |
   ssh remote@system tar -xzvf-
rm -rf tmp
    
por 23.08.2015 / 10:57
0

O GNU tar tem uma opção --delete :

$ tar -c a b c | tar --delete a | tar -t
b
c

Dessa forma, você pode obter um subconjunto do tar de entrada especificando o que não incluir na saída.

Infelizmente, não consegui usar a opção --exclude para trabalhar com --delete , portanto, primeiro você precisa obter uma lista explícita ( -t ) de itens a serem excluídos e depois passá-la para outra invocação de tar .

$ tar --delete --no-recursion 'tar -t --exclude subdir <some.tar' <some.tar | ssh ...

Ou você pode armazenar a lista em um arquivo externo, se for muito longo ou complexo:

$ tar -t --exclude subdir <some.tar >to_delete.lst
$ tar --delete --no-recursion -T to_delete.lst <some.tar | ssh ...
    
por 23.01.2017 / 15:34
-1

Pelo que sei, o comando tar não pode usar o formato tar ambos como entrada e saída. Você terá que extrair seus arquivos localmente de alguma forma, e usar o tar novamente para criar um tarfile on-the-fly, com algo assim (a - significa entrada / saída padrão é usada ao invés de um arquivo):

tar cf - subdir/ | ssh remote@system 'cd extractdir && tar xvf -'

Note que ter tar sendo capaz de extrair um arquivo tar diretamente em outro tarfile é uma idéia interessante ...

    
por 22.08.2015 / 23:20

Tags