Como posso compactar um arquivo no Linux no local, sem usar espaço em disco adicional?


20

Eu tenho uma unidade de 100 GB que tem um arquivo de 95 GB. Preciso liberar algum espaço na unidade (e agora não é possível transferir o arquivo da unidade). O arquivo seria compactado com gzipou com o que quer que bz2seja, mas todos esses programas gravam o arquivo compactado em um arquivo separado. Não tenho espaço livre suficiente para isso.

Existe uma maneira de usar ferramentas de compactação padrão ou outros utilitários Unix para compactar o arquivo sem usar espaço em disco adicional (ou pelo menos uma quantidade mínima de espaço em disco adicional)? Estou imaginando algo que comprime parte do arquivo por vez e grava os resultados diretamente sobre o arquivo. Sei que isso seria arriscado, pois o arquivo seria corrompido se a compactação fosse interrompida, mas acho que não tenho escolha.


Uma última opção que costumávamos usar na minha antiga casa era ter um diretório em algum lugar que continha um monte de arquivos 1G cheios de lixo. Então, se você entravar, poderá remover alguns deles para dar um pouco de espaço de emergência.

Respostas:


13

Esta é uma prova de conceito bash one-liner, mas deve começar. Use por sua conta e risco.

truncate -s `gzip -c file | dd of=file conv=notrunc 2>&1 | sed -n '$ s/ .*$// p'` file
mv file file.gz

Isso funciona canalizando dados gz para um processo dd que os grava novamente no mesmo arquivo. Após a conclusão, o arquivo é truncado para o tamanho da saída gz.

Isso pressupõe que a última linha da saída do dd corresponda:

4307 bytes (4,3 kB) copiados, 2,5855e-05 s, 167 MB / s

Onde o primeiro campo é um número inteiro de bytes gravados. Esse é o tamanho em que o arquivo precisará ser truncado. Não tenho 100% de certeza de que o formato de saída seja sempre o mesmo.


Truque bacana. Você poderia explicar por que conv=notruncé necessário?
sleske

Talvez não seja. gzip -c file | dd of=fileparece funcionar tão bem.
user710307

1
As pessoas na pergunta vinculada tentaram (e eu também tentei); não funciona em geral. Parece que funciona apenas para arquivos muito pequenos - talvez porque o gzip leia um arquivo pequeno na RAM antes de compactá-lo. Para arquivos grandes (alguns MB), ele não funciona, mesmo que sejam compactáveis.
sleske

3
Sim. Então conv = notrunc é necessário.
precisa saber é o seguinte

1
Não é possível que, a qualquer momento, o programa de compactação (por exemplo gzip) grave mais bytes de cabeçalho e de dados que os bytes de dados originais, substituindo algumas partes do arquivo? Eu acho que isso depende do programa de compactação escolhido. Alguém tem uma idéia de como impedir que isso aconteça ou quão (im) provável é?
Daniel Böhmer

7

Não é tanto isso gzipe bzip2sobrescreve o original. Em vez disso, eles gravam os dados compactados no disco como um novo arquivo e, se essa operação for bem-sucedida, desvincularão o arquivo original não compactado.

Se você tiver RAM suficiente, poderá escrever um script para compactar temporariamente os arquivos em um tmpfssistema de arquivos, remover o original no disco e substituí-lo pela versão compactada. Talvez algo parecido com isto:

# some distributions mount /dev/shm as tmpfs; replace with bzip2 if you prefer
if gzip -q9c /full/disk/somefile > /dev/shm/somefile.gz
then
    rm -f /full/disk/somefile && mv -i /dev/shm/somefile.gz /full/disk
fi

Apenas tenha em mente o uso de memória, pois tmpfsé essencialmente um disco RAM. Um arquivo de saída grande pode facilmente causar fome no sistema e causar outros problemas para você.


1
Isso é apenas o suficiente louco para o trabalho
Andrew Lambert

Eu gosto de empurrar o envelope.
James Sneeringer

3

Não existe ferramenta que funcione dessa maneira, exatamente pelo motivo que você indica. Poucas pessoas estão dispostas a escrever uma ferramenta que implemente deliberadamente comportamentos de risco.


Eu esperava que fosse uma opção insegura e não padrão para um utilitário. Você poderia pensar em uma alternativa? Existe uma maneira de truncar um arquivo no local para, por exemplo, remover os primeiros 2 GB? Isso me permitiria usar meu espaço livre limitado para compactar um pedaço de cada vez, reduzindo o arquivo de origem à medida que fui.
Lee

Não há realmente nenhuma maneira sensata de remover dados do início de um arquivo em qualquer sistema de arquivos, com qualquer ferramenta.
Ignacio Vazquez-Abrams

2
Mas você pode remover dados do final do arquivo. Isso pode ser feito em princípio. Você divide os dados do final do arquivo para colocar em arquivos separados, truncando os arquivos originais à medida que avança. Em seguida, você comprime os arquivos na ordem direta, excluindo-os à medida que avança. Seria difícil implementar e, se algo desse errado, você seria ferrado. Mas é possível.
David Schwartz

1

Os comandos split e csplit podem ser usados ​​para dividir o arquivo grande em partes menores e compactá-los individualmente. Remontar seria bastante demorado embora.


Outra boa opção. Provavelmente alguém poderia escrever algum script para fazer isso. No entanto, isso gera muitos arquivos compactados separadamente, que precisarão ser re-concatenados após a descompactação, o que não é tão bom.
sleske
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.