Parece que tar
quer saber todos os nomes dos arquivos antecipadamente. Por isso, é menos on-the-fly e mais after-the-fly. cpio
parece não ter esse problema:
| cpio -vo 2>&1 > >(gzip > /tmp/arc.cpio.gz) | parallel rm
Eu tenho um processo embaraçosamente paralelo que cria uma enorme quantidade de quase (mas não completamente) arquivos idênticos. Existe uma maneira de arquivar os arquivos "on the fly", para que os dados não consumam mais espaço do que o necessário?
O próprio processo aceita parâmetros de linha de comando e imprime o nome de cada arquivo criado para stdout. Estou chamando-o com parallel --gnu
, que cuida da distribuição de entrada (que vem de outro processo) e coleta de saída:
arg_generating_process | parallel --gnu my_process | magic_otf_compressor
EXEMPLO SIMPLES para a primeira parte do pipe em bash
:
for ((f = 0; $f < 100000; f++)); do touch $f; echo $f; done
Como pode ser magic_otf_compressor
? É suposto tratar cada linha de entrada como nome de arquivo, copiar cada arquivo para um% compactado.tar
archive (o mesmo arquivo para todos os arquivos processados!) E, em seguida, excluí-lo. (Na verdade, deve ser o suficiente para imprimir o nome de cada arquivo processado, outro | parallel --gnu rm
pode cuidar da exclusão dos arquivos.)
Existe alguma ferramenta desse tipo? Eu não estou pensando em compactar cada arquivo individualmente, isso iria desperdiçar muito espaço. Eu olhei em archivemount
(manterá o sistema de arquivos na memória - > impossível, meus arquivos são muito grandes e muitos) e avfs
(não consegui fazê-lo funcionar junto com o FUSE). O que eu perdi?
Estou a apenas um passo de invadir essa ferramenta, mas alguém deve ter feito isso antes ...
EDIT : Essencialmente, acho que estou procurando um front-end de stdin para libtar
(em oposição ao front-end de linha de comando tar
que lê argumentos de, bem, a linha de comando).
Um caso clássico de RTFM (tudo isso!) . A opção -T
para GNU tar
lerá os arquivos a serem arquivados de outro arquivo (no meu caso, /dev/stdin
, você também pode usar -
), e há até mesmo uma opção --remove-files
:
alias magic_otf_compressor='tar --create -T - --remove-files -O | pixz'
(usando a versão paralela de xz
para compactação, mas você pode usar o seu compressor preferido). Para ser usado como:
arg_generating_process |
parallel --gnu my_process |
magic_otf_compressor > file.tar.xz
EDIT : Como Ole aponta, tar
parece ler toda a lista de arquivos com a opção -T
por algum motivo. O teste a seguir confirma isso:
for ((f = 0; $f < 1000; f++)); do
touch $f; echo $f;
done | tar -c -f otf.tar -T - -v
Há um atraso de um segundo no meu sistema antes que todos os arquivos sejam impressos de uma só vez; Por outro lado, se o comando tar
for substituído por cat
, todos os arquivos serão impressos à medida que forem criados. Eu arquivei uma solicitação de suporte com o pessoal do tar, vamos ver.
EDIT ^ 2 : O mais recente tar
da origem corrige isso. Ainda não está no Ubuntu 13.10, mas pode estar incluído no 14.04.
De alguma forma, isso não parece ser um bom trabalho para um compressor sólido (arquivadores baseados em fita + compactação). A inserção de arquivos um após o outro parece um trabalho para zip
ou algum outro formato que permita acesso aleatório a arquivos no arquivo e inserção incremental.
O fato de os arquivos serem semelhantes não ajuda muito em nenhum dos casos. Em zip
, os arquivos são compactados separadamente e, em compressores sólidos, geralmente há uma janela na qual a compactação ocorre.
Se os arquivos forem baseados em texto, você poderá armazenar os diffs em comparação com um único arquivo de referência. Para binário, é um pouco mais complicado, mas pode ser feito.
Há também uma maneira formal (não apenas de gravação, mas sistemas de arquivos apropriados). Por exemplo, os sistemas de arquivos ZFS e BTRFS oferecem compactação transparente. Você também pode usar este link
Pode não parecer óbvio, mas aposto que squashfs
seria perfeito para isso - e é mesmo implementado no kernel. Como a versão 4.1 squashfs
pode manipular pseudo arquivos conforme especificado na linha de comando mksquash
ou através de um script shell e mksquashfs
gerará os arquivos conforme cria o arquivo.
Ele pode manipular pipes - por exemplo, você pode capturar stdout
de outro processo em um arquivo de squash montável - até fifos - é bem legal. No seu caso, se você pudesse elaborar a logística do script de canalizar a saída do seu processo através dela, você poderia envolver completamente o seu processo em mksquashfs
e acabar com um único arquivo. Aqui está um pouco do readme
sobre como funciona e há mais aqui :
Mksquashfs 4.1 adds support for "dynamic pseudo files" and a modify operation. Dynamic pseudo files allow files to be dynamically created when Mksquashfs is run, their contents being the result of running a command or piece of shell script. The modifiy operation allows the mode/uid/gid of an existing file in the source filesystem to be modified.
Creating dynamic file examples
Create a file "dmesg" containing the output from dmesg.
dmesg f 444 root root dmesg
Create a file RELEASE containing the release name, date, build host, and an incrementing version number. The incrementing version is a side-effect of executing the shell script, and ensures every time Mksquashfs is run a new version number is used without requiring any other shell scripting.
RELEASE f 444 root root \
if [ ! -e /tmp/ver ]; then \
echo 0 > /tmp/ver; \
fi; \
ver='cat /tmp/ver'; \
ver=$((ver +1)); \
echo $ver > /tmp/ver; \
echo -n "release x.x"; \
echo "-dev #"$ver 'date' "Build host" 'hostname'
Copy 10K from the device /dev/sda1 into the file input. Ordinarily Mksquashfs given a device, fifo, or named socket will place that special file within the Squashfs filesystem, this allows input from these special files to be captured and placed in the Squashfs filesystem.
input f 444 root root dd if=/dev/sda1 bs=1024 count=10
Tags tar fuse filesystems parallelism