Comprimir um arquivo no lugar - faz “gzip -c file | dd of = file ”realmente funciona?

6

Na pergunta Como posso compactar um arquivo no Linux no local, sem usar espaço em disco adicional? , uma resposta propõe simplesmente usar

gzip -c file | dd of=file

Eu tentei (no Debian Linux), e parece funcionar. Eu não entendo muito bem porque, no entanto.

Não dd truncar o arquivo de saída antes de gravar? Isso não seria "extrair o tapete" em gzip , tirando assim os dados que o gzip quer ler?

Ou há alguma condição de corrida envolvida, o que significa que o comando geralmente funciona, mas às vezes pode falhar? Ou de alguma forma depende do tamanho dos blocos que os comandos usam para E / S?

Eu sei que um processo que abriu um arquivo pode continuar lendo mesmo que outro processo o apague (o arquivo será descartado assim que o processo for fechado). Existe um mecanismo similar se um arquivo é truncado enquanto algum processo o abre?

    
por sleske 18.01.2012 / 09:23

1 resposta

4

A experiência mostra que isso não funciona .

Eu criei um arquivo de 2 megabytes a partir de /dev/urandom e, em seguida, testei o comando acima nele. Aqui estão os resultados:

% ls -l
total 41008
-rw-r--r-- 1 kst kst 20971520 2012-01-18 03:47 file
-rw-r--r-- 1 kst kst 20971520 2012-01-18 02:48 orig
% gzip -c file | dd of=file
0+1 records in
0+1 records out
25 bytes (25 B) copied, 0.000118005 s, 212 kB/s
% ls -l
total 20508
-rw-r--r-- 1 kst kst       25 2012-01-18 03:47 file
-rw-r--r-- 1 kst kst 20971520 2012-01-18 02:48 orig
$ 

Obviamente, um arquivo aleatório de 2 megabytes não é compactado em 25 bytes e, na verdade, a execução de gunzip no arquivo compactado gera um arquivo vazio.

Eu obtive resultados semelhantes para um arquivo aleatório muito menor (100 bytes).

Então, o que aconteceu?

Nesse caso, o comando dd truncou file para zero bytes antes de começar a gravar nele; gzip começou a ler o arquivo recém-vazio e produziu 25 bytes de saída, que dd anexou ao file vazio. (Um arquivo vazio "comprime" para um tamanho diferente de zero; é teoricamente impossível para qualquer compressor tornar a entrada all menor).

Outros resultados podem ser possíveis, dependendo do tempo dos processos gzip , dd e shell, todos em execução paralelamente.

Há uma condição de corrida porque um processo, gzip , lê a partir de file , enquanto outro processo paralelo, o shell, grava nele.

Deve ser possível implementar um compressor de arquivo no local que leia e grave no mesmo arquivo, usando qualquer buffer interno necessário para evitar a perda de dados. Mas eu nunca ouvi falar de alguém realmente implementando isso, provavelmente porque geralmente não é necessário e porque se o compressor falhar no meio do caminho, o arquivo será permanentemente corrompido.

    
por 18.01.2012 / 12:51