Extrair arquivo tar tar


14

Eu tenho um pequeno dilema aqui ...

Eu precisava mover cerca de 70 GB de arquivos de um dos meus servidores para outro, então decidi que ordená-los e enviar o arquivo seria a maneira mais rápida.

No entanto, o servidor de recebimento tem apenas 5 GB de espaço restante após receber o arquivo tar.

Existe alguma maneira de extrair o alcatrão 'no local'? Não preciso manter o arquivo depois que ele foi extraído, por isso fiquei pensando se é possível fazer isso.

Edit: Note-se que o arquivo já foi enviado, e eu gostaria de evitar reenviar através de um método diferente.

Respostas:


11
% tar czf - stuff_to_backup | ssh backupmachine tar xvzf -

isso se traduz em:

  • tar e comprimir 'stuff_to_backup' para stdout
  • faça login em 'backupmachine' via ssh
  • execute 'tar' na 'máquina de backup' e descompacte o material que vem de stdin

Eu pessoalmente usaria 'rsync over ssh' para transferir as coisas, porque você pode continuar transferindo as coisas se a conexão quebrar:

% rsync -ar --progress -e 'ssh' 'stuff_to_backup' user@backupmachine:/backup/

que transferirá tudo de 'stuff_to_backup' para a pasta 'backup' na 'máquina de backup'. se a conexão quebrar, basta repetir o comando. se alguns arquivos em 'stuff_to_backup' mudarem, repita o material, apenas a diferença será transferida.


Veja minha pergunta editada
covarde anônimo

@ Charlie Somerville: sim, você deixou a parte importante de fora em primeiro lugar. :)
akira

6

Se a outra máquina tiver ssh, eu recomendaria o rsync como outra alternativa que não use um arquivo tar:

rsync -avPz /some/dir/ user@machine:/some/other/dir/

E tenha cuidado com os principais /

Editar atualização

Bem, vejo como isso agora é uma ótima opção se você não conseguir excluí-lo e recomeçar com o rsync. Eu provavelmente tentaria um extrato seletivo e excluiria do alcatrão.

extrato seletivo:

$ tar xvf googlecl-0.9.7.tar googlecl-0.9.7/README.txt
googlecl-0.9.7/README.txt

exclusão seletiva:

$ tar --delete --file=googlecl-0.9.7.tar googlecl-0.9.7/README.txt

No entanto, parece que você passará muito tempo codificando um script para isso ...


Veja minha pergunta editada
covarde anônimo

Veja minha resposta editada ... boa sorte: - /
YuppieNetworking

Obrigado pela edição. Na verdade, os arquivos são nomeados com números; portanto, um rápido loop no bash pode fazer o truque.
covarde anônimo

1
@ Charlie Somerville: você pode ter que começar com os arquivos armazenados no final do tar, caso contrário, pode acabar com o tar criando um novo arquivo ... então exclua os arquivos do final do tar primeiro.
akira

5

Basicamente, o que você precisa é a possibilidade de inserir o arquivo no alcatrão e "cortar" a frente à medida que avança.

No StackOverflow, alguém perguntou como truncar um arquivo na frente , mas parece que não é possível. Você ainda pode preencher o início do arquivo com zeros de uma maneira especial, para que o arquivo se torne um arquivo esparso , mas não sei como fazer isso. No entanto, podemos truncar o final do arquivo. Mas o tar precisa ler o arquivo para a frente, não para trás.

Solução 1

Um nível de indireção resolve todos os problemas. Primeiro inverta o arquivo no local, depois leia-o para trás (o que resultará na leitura do arquivo original para a frente) e trunque o final do arquivo invertido à medida que avança.

Você precisará escrever um programa (c, python, qualquer que seja) para trocar o início e o final do arquivo, pedaço por pedaço, e depois canalizar esses pedaços para tar, enquanto trunca o arquivo um pedaço por vez. Essa é a base da solução 2, que talvez seja mais simples de implementar.

Solução 2

Outro método é dividir o arquivo em pequenos pedaços no local e excluí-los à medida que os extraímos. O código abaixo tem um tamanho de bloco de um megabyte, ajuste de acordo com suas necessidades. Maior é mais rápido, mas ocupa mais espaço intermediário ao dividir e durante a extração.

Divida o arquivo archive.tar:

archive="archive.tar"
chunkprefix="chunk_"
# 1-Mb chunks :
chunksize=1048576

totalsize=$(wc -c "$archive" | cut -d ' ' -f 1)
currentchunk=$(((totalsize-1)/chunksize))
while [ $currentchunk -ge 0 ]; do
    # Print current chunk number, so we know it is still running.
    echo -n "$currentchunk "
    offset=$((currentchunk*chunksize))
    # Copy end of $archive to new file
    tail -c +$((offset+1)) "$archive" > "$chunkprefix$currentchunk"
    # Chop end of $archive
    truncate -s $offset "$archive"
    currentchunk=$((currentchunk-1))
done

Canalize esses arquivos no tar (observe que precisamos da variável chunkprefix no segundo terminal):

mkfifo fifo
# In one terminal :
(while true; do cat fifo; done) | tar -xf -
# In another terminal :
chunkprefix="chunk_"
currentchunk=0
while [ -e "$chunkprefix$currentchunk" ]; do
    cat "$chunkprefix$currentchunk" && rm -f "$chunkprefix$currentchunk"
    currentchunk=$((currentchunk+1))
done > fifo
# When second terminal has finished :
# flush caches to disk :
sync
# wait 5 minutes so we're sure tar has consumed everything from the fifo.
sleep 300
rm fifo
# And kill (ctrl-C) the tar command in the other terminal.

Como usamos um pipe nomeado ( mkfifo fifo), você não precisa canalizar todos os pedaços de uma só vez. Isso pode ser útil se você estiver realmente com pouco espaço. Você pode seguir as seguintes etapas:

  • Mova, digamos os últimos blocos de 10 GB para outro disco,
  • Comece a extração com os pedaços que você ainda tem,
  • Quando o while [ -e … ]; do cat "$chunk…; doneloop terminar (segundo terminal):
  • NÃO pare o tarcomando, NÃO remova o fifo (primeiro terminal), mas você pode executar sync, por precaução,
  • Mova alguns arquivos extraídos que você sabe que estão completos (o tar não está parado aguardando a conclusão dos dados para extrair esses arquivos) para outro disco,
  • Mova os pedaços restantes para trás,
  • Continue a extração executando as while [ -e … ]; do cat "$chunk…; donelinhas novamente.

É claro que tudo isso é de alta tensão , você deve verificar primeiro se tudo está bem em um arquivo fictício, porque se você cometer um erro, adeus aos dados .

Você nunca saberá se o primeiro terminal ( tar) realmente terminou o processamento do conteúdo do fifo; portanto, se preferir, execute isso em vez disso, mas não terá a possibilidade de trocar facilmente pedaços com outro disco:

chunkprefix="chunk_"
currentchunk=0
while [ -e "$chunkprefix$currentchunk" ]; do
    cat "$chunkprefix$currentchunk" && rm -f "$chunkprefix$currentchunk"
    currentchunk=$((currentchunk+1))
done | tar -xf -

aviso Legal

Observe que, para que tudo isso funcione, seu shell, cauda e truncado devem manipular números inteiros de 64 bits corretamente (você não precisa de um computador de 64 bits nem de um sistema operacional para isso). O meu funciona, mas se você executar o script acima em um sistema sem esses requisitos, perderá todos os dados em archive.tar .

E, em qualquer caso, algo que não dê errado, você perderá todos os dados em archive.tar de qualquer maneira, portanto, certifique-se de ter um backup dos seus dados.


0

Se você tiver arquivos de objetos a serem movidos, tente removê-los. Isso economizará uma quantidade considerável de espaço.

$ strip `find . -name "*.bin"`
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.