Usando 'head' ou 'tail' no arquivo de texto ENORME - 19 GB


14

Estou com um problema ao visualizar blocos de um arquivo de texto muito grande. Esse arquivo, aproximadamente 19 GB, é obviamente grande demais para ser visualizado por qualquer meio tradicional.

Eu tentei head 1e tail 1( head -n 1e tail -n 1) com os dois comandos reunidos de várias maneiras (para chegar a um pedaço no meio) sem sorte. Minha máquina Linux executando o Ubuntu 9.10 não pode processar este arquivo.

Como eu manejo esse arquivo? Meu objetivo final é aprimorar as linhas 45000000 e 45000100.


Pensando em escrever um Python script rápido para ler as linhas e imprimir os que eu preciso para o arquivo, mas posso imaginar esta a demorar muito tempo ...
nicorellius

Todas as linhas têm o mesmo comprimento?
Paul

@ Paul - infelizmente, eles não têm o mesmo comprimento.
21412 nicorellius

Você pode tentar splitfacilitar o trabalho do arquivo grande.
iglvzx

1
Está bem. Qualquer processamento de um arquivo desse tamanho levará tempo, portanto as respostas abaixo o ajudarão. Se você deseja extrair apenas a parte que está procurando e pode estimar aproximadamente onde está, pode usar ddpara obter a parte que procura . Por exemplo dd if=bigfile of=extractfile bs=1M skip=10240 count=5, extrairá 5 MB do arquivo a partir do ponto de 10 GB.
Paul

Respostas:


11

Você deveria usar sed.

sed -n -e 45000000,45000100p -e 45000101q bigfile > savedlines

Isso indica sedpara imprimir as linhas 45000000-45000100 inclusive e sair na linha 45000101.


1
Ainda está muito lento, quase como o cabeça -45000000,45000100p bigfile | tail -100> savedlines
Dmitry Polushkin

tail+|headé mais rápido em 10-15%.
Erich

4

Crie um banco de dados MySQL com uma única tabela que possui um único campo. Em seguida, importe seu arquivo para o banco de dados. Isso tornará muito fácil procurar uma determinada linha.

Acho que nada mais poderia ser mais rápido (se heade tailjá falhar). No final, o aplicativo que deseja localizar a linha ndeve procurar por todo o arquivo até encontrar nnovas linhas. Sem algum tipo de pesquisa (deslocamento do índice de linha para byte no arquivo), não é possível obter melhor desempenho.

Dado o quão fácil é criar um banco de dados MySQL e importar dados para ele, sinto que essa é uma abordagem viável.

Aqui está como fazê-lo:

DROP DATABASE IF EXISTS helperDb;
CREATE DATABASE `helperDb`;
CREATE TABLE `helperDb`.`helperTable`( `lineIndex` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `lineContent` MEDIUMTEXT , PRIMARY KEY (`lineIndex`) );
LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable (lineContent);
SELECT lineContent FROM helperTable WHERE ( lineIndex > 45000000 AND lineIndex < 45000100 );

/tmp/my_large_file seria o arquivo que você deseja ler.

A sintaxe correta para importar um arquivo com valores delimitados por tabulação em cada linha é:

LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable FIELDS TERMINATED BY '\n' (lineContent);

Outra grande vantagem disso é que, se você decidir posteriormente extrair outro conjunto de linhas, não precisará esperar horas pelo processamento novamente (a menos que exclua o banco de dados, é claro).


Portanto, esta é uma boa solução, de fato. Consegui trabalhar com o sedcomando abaixo e identifiquei minhas linhas. Mas agora tenho uma pergunta de acompanhamento para a qual o método de banco de dados pode ser mais adequado. Agora preciso excluir algumas centenas de linhas do arquivo.
22612 nicorellius

Tenho certeza que sedpoderia fazer isso também. Obviamente, se você tivesse os dados no banco de dados, seria trivial exportar um novo arquivo com apenas as linhas desejadas.
Der Hochstapler

Obrigado novamente. Peguei a sedresposta (porque isso me deu um prazer mais imediato; -), mas lhe dei uma votação positiva, porque usarei seu método no futuro. Eu agradeço.
22612 nicorellius

1
Você pode tentar adicionar um FIELDS TERMINATED BY '\n'à LOAD DATAlinha.
Der Hochstapler

1
Sinto muito, houve um erro no meu código. Também adicionei a sintaxe correta para o seu caso (testado desta vez).
Der Hochstapler

1

Duas boas ferramentas antigas para arquivos grandes são joine split. Você pode usar o split com a --lines=<number>opção de cortar arquivos em vários arquivos de determinado tamanho.

Por exemplo split --lines=45000000 huge_file.txt. As partes resultantes estariam em xa, xb, etc. Em seguida, você pode heada parte xb que incluirá as linhas que você deseja. Você também pode 'ingressar' nos arquivos novamente para um único arquivo grande.


Impressionante, obrigado, esqueci completamente o comando split.
precisa saber é o seguinte

0

Você tem as ferramentas certas, mas as está usando incorretamente. Como respondido anteriormente na U&L, tail -n +X file | head -n Y(observe +) é 10-15% mais rápido do que sednas linhas Y começando em X. E, convenientemente, você não precisa explicitamente exito processo como no caso sed.

tail lerá e descartará as primeiras linhas X-1 (não há como contornar isso), depois lerá e imprimirá as seguintes linhas. O cabeçalho lê e imprime o número solicitado de linhas e sai. Quando o cabeçote sai, a cauda recebe um sinal SIGPIPE e morre, para que não tenha lido mais do que o tamanho de um buffer (normalmente alguns kilobytes) de linhas do arquivo de entrada.

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.