Tenho certeza que alguém teve a necessidade abaixo, qual é uma maneira rápida de dividir um arquivo .gz enorme por linha? O arquivo de texto subjacente possui 120 milhões de linhas. Eu não tenho espaço em disco suficiente para compactar o arquivo inteiro de uma só vez, então eu queria saber se alguém conhece um script ou ferramenta bash / perl que possa dividir o arquivo (o .gz ou o .txt interno) em arquivos de linha de 3x 40mn . ou seja, chamando assim:
bash splitter.sh hugefile.txt.gz 4000000 1
would get lines 1 to 40 mn
bash splitter.sh hugefile.txt.gz 4000000 2
would get lines 40mn to 80 mn
bash splitter.sh hugefile.txt.gz 4000000 3
would get lines 80mn to 120 mn
Talvez esteja fazendo uma série dessas soluções ou o gunzip -c exigiria espaço suficiente para que o arquivo inteiro fosse descompactado (ou seja, o problema original): gunzip -c hugefile.txt.gz | cabeça 4000000
Nota: Não consigo obter disco extra.
Obrigado!
Respostas:
Como fazer isso melhor depende do que você deseja:
Se você deseja uma única parte do arquivo , sua ideia é usar
gunzip
ehead
está certa. Você pode usar:Isso produziria as primeiras 4000000 linhas na saída padrão - você provavelmente deseja acrescentar outro canal para realmente fazer alguma coisa com os dados.
Para obter as outras partes, você usaria uma combinação de
head
etail
, como:para pegar o segundo bloco.
Não,
gunzip -c
ele não requer espaço em disco - ele faz tudo na memória e o envia para o stdout.Se você deseja criar todas as partes de uma só vez , é mais eficiente criá-las todas com um único comando, porque o arquivo de entrada é lido apenas uma vez. Uma boa solução é usar
split
; veja a resposta de jim mcnamara para obter detalhes.fonte
gzip
não sabe sobre o limite (que vem de um processo diferente). Sehead
for usado,head
sairá quando tiver recebido o suficiente, e isso será propagado paragzip
(via SIGPIPE, consulte Wikipedia). Comotail
isso não é possível, então sim,gzip
descomprimirá tudo.pipe para dividir use gunzip -c ou zcat para abrir o arquivo
Adicione especificações de saída ao comando de divisão.
fonte
Enquanto você está trabalhando em um fluxo (não rebobinável), convém usar a forma '+ N' de cauda para obter linhas começando na linha N em diante.
fonte
Eu consideraria usar split .
fonte
Divida diretamente o arquivo .gz em arquivos .gz:
Eu acho que é isso que o OP queria, porque ele não tem muito espaço.
fonte
Aqui está um script python para abrir um conjunto global de arquivos de um diretório, compactá-los, se necessário, e lê-los linha por linha. Ele usa apenas o espaço necessário na memória para armazenar os nomes de arquivos e a linha atual, além de um pouco de sobrecarga.
O comando print line envia todas as linhas para std, para que você possa redirecionar para um arquivo. Como alternativa, se você nos informar o que deseja fazer com as linhas, eu posso adicioná-lo ao script python e você não precisará deixar pedaços do arquivo por aí.
fonte
Aqui está um programa perl que pode ser usado para ler stdin e dividir as linhas, canalizando cada grupo para um comando separado que pode usar uma variável de shell $ SPLIT para rotear para um destino diferente. Para o seu caso, seria invocado com
zcat hugefile.txt.gz | perl xsplit.pl 40000000 'cat > tmp$SPLIT.txt; do_something tmp$SPLIT.txt; rm tmp$SPLIT.txt'
Desculpe, o processamento da linha de comando é um pouco complicado, mas você entendeu.
fonte