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…; done
loop terminar (segundo terminal):
- NÃO pare o
tar
comando, 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…; done
linhas 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.