Eu tenho um arquivo .msg bastante grande formatado no formato UIEE.
$ wc -l big_db.msg
8726593 big_db.msg
Essencialmente, o arquivo é composto de entradas de vários tamanhos que se parecem com isso:
UR|1
AA|Condon, Richard
TI|Prizzi's Family
CN|Collectable- Good/Good
MT|FICTION
PU|G.P. Putnam & Sons
DP|1986
ED|First Printing.
BD|Hard Cover
NT|0399132104
KE|MAFIA
KE|FICTION
PR|44.9
XA|4
XB|1
XC|BO
XD|S
UR|10
AA|Gariepy, Henry
TI|Portraits of Perseverance
CN|Good/No Jacket
MT|SOLD
PU|Victor Books
DP|1989
BD|Mass Market Paperback
NT|1989 tpb g 100 meditations from the Book of Job "This book...help you
NT| persevere through the struggles of your life..."
KE|Bible
KE|religion
KE|Job
KE|meditations
PR|28.4
XA|4
XB|5
XC|BO
XD|S
Este é um exemplo de duas entradas, separadas por uma linha em branco. Desejo dividir esse arquivo grande em arquivos menores sem quebrar uma entrada em dois arquivos.
Cada entrada individual é separada por uma nova linha (uma linha completamente em branco) no arquivo. Desejo dividir esse arquivo de linha de 8,7 milhões em 15 arquivos. Entendo que split
existem ferramentas como essa, mas não tenho certeza de como dividir o arquivo, mas apenas o dividi em uma nova linha, para que uma única entrada não seja dividida em vários arquivos.
text-processing
split
user2036066
fonte
fonte
csplit
também existe.|
(comoUR
,AA
,TI
) relevante para a contagem de arquivos, mesmo a mesma para ser exato?Respostas:
Aqui está uma solução que poderia funcionar:
Funciona permitindo que o primeiro
sed
escreva osed
script do segundo . O segundosed
primeiro reúne todas as linhas de entrada até encontrar uma linha em branco. Em seguida, ele grava todas as linhas de saída em um arquivo. O primeirosed
escreve um script para o segundo, instruindo-o sobre onde escrever sua saída. No meu caso de teste, esse script ficou assim:Eu testei assim:
Isso me forneceu um arquivo de 6000 linhas, com a seguinte aparência:
... repetido 1000 vezes.
Depois de executar o script acima:
RESULTADO
fonte
Usando a sugestão de
csplit
:Divisão com base nos números de linha
Exemplo
Digamos que eu tenha um arquivo com 1000 linhas.
resulta em arquivos assim:
Você pode contornar a limitação estática de precisar especificar o número de repetições pré-calculando os números com base no número de linhas em seu arquivo específico com antecedência.
Divisão com base em linhas em branco
Se, por outro lado, você deseja simplesmente dividir um arquivo em linhas em branco contidas no arquivo, você pode usar esta versão
split
:Exemplo
Digamos que adicionei 4 linhas em branco ao texto
file.txt
acima e crie o arquivofile2.txt
. Você pode ver que eles foram adicionados manualmente da seguinte forma:O exemplo acima mostra que eu os adicionei entre os números correspondentes no meu arquivo de amostra. Agora, quando eu executo o
csplit
comando:Você pode ver que agora tenho 4 arquivos que foram divididos com base na linha em branco:
Referências
fonte
Se você não se importa com os pedidos dos registros, pode:
Caso contrário, você precisará primeiro obter o número de registros primeiro e saber quantos colocar em cada arquivo de saída:
fonte
file.in
efile.out
?Se você deseja dividir apenas no final de uma linha, poderá fazê-lo com a
-l
opção forsplit
.Se você deseja dividir em uma linha em branco (
\n\n
), aqui está como eu faria isso em ksh. Não testei e provavelmente não é o ideal, mas algo nessa linha funcionaria:fonte
\n\n
, eu acho.\n\n
, mas sim para não dividir no meio de uma linha. Ele está chamando uma nova linha de uma linha em branco.Tentar
awk
fonte
Se você não se importa com a ordem dos registros, mas com particular interesse em obter um certo número de arquivos de saída, a resposta de Stephane é a maneira que eu iria. Mas tenho a sensação de que você pode se importar mais em especificar um tamanho que cada arquivo de saída não deve exceder. Isso realmente facilita, porque você pode ler seu arquivo de entrada e coletar registros até atingir esse tamanho e, em seguida, iniciar um novo arquivo de saída. Se isso funcionar para você, a maioria das linguagens de programação pode lidar com sua tarefa com um script curto. Aqui está uma implementação awk:
Coloque isso em um arquivo, digamos
program.awk
, e execute-o comawk -v maxlen=10000 -f program.awk big_db.msg
o valor demaxlen
mais bytes desejados em qualquer arquivo. Ele usará 500k como padrão.Se você deseja obter um número definido de arquivos, provavelmente a maneira mais fácil é apenas dividir o tamanho do arquivo de entrada pelo número de arquivos que deseja e, em seguida, adicionar um pouco ao número a ser obtido
maxlen
. Por exemplo, para obter 15 arquivos dos seus 8726593 bytes, divida por 15 para obter 581773 e adicione alguns, talvez dêmaxlen=590000
oumaxlen=600000
. Se você quiser fazer isso repetidamente, seria possível configurar o programa para fazer isso.fonte