2015-10-23 2 views
10

У меня возникли проблемы с разбиением большого текстового файла на несколько более мелких. Синтаксис моего текстового файла заключается в следующем:Разделение большого текстового файла на каждую пустую строку

dasdas #42319 blaablaa 50 50 
content content 
more content 
content conclusion 

asdasd #92012 blaablaa 30 70 
content again 
more of it 
content conclusion 

asdasd #299 yadayada 60 40 
content 
content 
contend done 
...and so on 

(Dasdas # 42319 blaablaa 50 50, содержание контента, больше контента & содержания вывода все свои отдельные линии следует пустой строка конец этой информационной таблицы . Типичная информационная таблица в моем файле имеет место между 10-40 строками.)

Я бы хотел, чтобы этот файл был разбит на n меньших файлов, где n - количество таблиц содержимого.
Это

dasdas #42319 blaablaa 50 50 
content content 
more content 
content conclusion 

бы это собственный отдельно файл (whateverN.txt)

и

asdasd #92012 blaablaa 30 70 
content again 
more of it 
content conclusion 

снова отдельный файл whateverN + 1.txt и так далее.

Похоже, что или Perl являются отличными инструментами для этого, но никогда не использовали их до того, как синтаксис выглядит непонятным.

Я нашел эти два вопроса, которые почти соответствуют моей проблеме, но не смогли изменить синтаксис в соответствии с моими потребностями.

Split text file into multiple files &
https://unix.stackexchange.com/questions/46325/how-can-i-split-a-text-file-into-multiple-text-files

Как следует изменить входные данные из командной строки, так что он решает мою проблему?

+2

Бьюсь вам нужно узнать, как использовать их (AWK, Perl, или любой другой) немного, прежде чем пытаться использовать их, чтобы решить свои проблемы , –

+0

Или есть язык, на котором вы знаете, что вы можете попробовать решение? – mwp

+0

Обратите внимание на [edit-help] (http://stackoverflow.com/editing-help). – Cyrus

ответ

0

Поскольку это пятница, и я чувствую себя немного полезно ... :)

Попробуйте это. Если файл такой же маленький, как вы подразумеваете, просто прочесть его все сразу и работать в памяти.

use strict; 
use warnings; 

# slurp file 
local $/ = undef; 
open my $fh, '<', 'test.txt' or die $!; 
my $text = <$fh>; 
close $fh; 

# split on double new line 
my @chunks = split(/\n\n/, $text); 

# make new files from chunks 
my $count = 1; 
for my $chunk (@chunks) { 
    open my $ofh, '>', "whatever$count.txt" or die $!; 
    print $ofh $chunk, "\n"; 
    close $ofh; 
    $count++; 
} 

В perl документы могут объяснить любые отдельные команды, которые не понимают, но в этот момент вы, вероятно, следует искать в учебнике, а также.

+0

Настройка '$ /', вероятно, является лучшим подходом. – Sobrique

+0

Правда, и «местный» тоже не нужен. Сила привычки. –

+0

Это хорошая привычка, хотя и другая, которая ничего не вредит;) – Sobrique

1

Вы можете использовать этот awk,

awk 'BEGIN{file="content"++i".txt"} !NF{file="content"++i".txt";next} {print > file}' yourfile 

(OR)

awk 'BEGIN{i++} !NF{++i;next} {print > "filename"i".txt"}' yourfile 

Более читаемый формат:

BEGIN { 
     file="content"++i".txt" 
} 
!NF { 
     file="content"++i".txt"; 
     next 
} 
{ 
     print > file 
} 
+0

Вместо '$ 0 ~/^ $ /' вы могли бы просто использовать '/^$ /' или чаще '! NF'. Вы хотите 'print> file', а не' print >> file' - shell и awk имеют разную семантику для '>' vs '>>'. –

+1

@ Эдмонтон, ты прав. Обновлено. Спасибо за подсказку ('shell' и' awk' имеют разную семантику для '>' vs '>>'). – sat

+0

Используйте 'print> (" filename "i" .txt ")' вместо 'print>" filename "i" .txt ", поскольку значение этого утверждения не определено в POSIX, и некоторые awll будут рассматривать его как' (print > "filename") i ".txt" или что-то еще нежелательное. –

0
awk -v RS="\n\n" '{for (i=1;i<=NR;i++); print > i-1}' file.txt 

Наборы разделитель записей, как пустая строка, печатает каждый записывать как один файл с номером 1, 2, 3 и т. д. Последний файл (только) заканчивается пустой строкой.

+0

Использование нескольких символов для RS делает этот gawk конкретным, но вы должны использовать 'RS =" "' так или иначе. Также всегда скопируйте правую сторону перенаправления вывода, поскольку некоторые awks будут интерпретировать 'print i-1' как' (print i) -i'. Самое главное - логика ошибочна, и она будет печатать записи NR каждой записи. –

0

Попробуйте этот Баш скрипт также

#!/bin/bash 
i=1 
fileName="OutputFile_$i" 
while read line ; do 
if [ "$line" == "" ] ; then 
((++i)) 
fileName="OutputFile_$i" 
else 
echo $line >> "$fileName" 
fi 
done < InputFile.txt 
+0

Это испортит содержимое его входного файла и произведет другой вывод, основанный на содержимом входного файла, плюс содержимое любого каталога, из которого вы его запускаете. НЕ пишите петли оболочки, чтобы манипулировать текстом. См. Http: //unix.stackexchange.com/q/169716/133219 –

15

Установка RS в нуль говорит AWK использовать один или несколько пустых строк как разделитель записей. Тогда вы можете просто использовать NR, чтобы задать имя файла, соответствующего каждой новой записи:

awk -v RS= '{print > ("whatever-" NR ".txt")}' file.txt 

RS: Это входной разделитель записей AWK в. Его значением по умолчанию является строка, содержащая один символ новой строки, что означает, что входная запись состоит из одной строки текста. Он также может быть пустой строкой, в этом случае записи разделяются пробелами пустых строк или регулярным выражением, в этом случае записи разделяются совпадением регулярного выражения во входном тексте.

$ cat file.txt 
dasdas #42319 blaablaa 50 50 
content content 
more content 
content conclusion 

asdasd #92012 blaablaa 30 70 
content again 
more of it 
content conclusion 

asdasd #299 yadayada 60 40 
content 
content 
contend done 

$ awk -v RS= '{print > ("whatever-" NR ".txt")}' file.txt 

$ ls whatever-*.txt 
whatever-1.txt whatever-2.txt whatever-3.txt 

$ cat whatever-1.txt 
dasdas #42319 blaablaa 50 50 
content content 
more content 
content conclusion 

$ cat whatever-2.txt 
asdasd #92012 blaablaa 30 70 
content again 
more of it 
content conclusion 

$ cat whatever-3.txt 
asdasd #299 yadayada 60 40 
content 
content 
contend done 
$ 
+1

Yup, вот как вы это делаете, +1. –

+0

Как сохранить его в переменном массиве? – Chand

3

Perl, обладает полезной функцией называется входной разделитель записей. $/.

Это «маркер» для разделения записей при чтении файла.

Итак:

#!/usr/bin/env perl 
use strict; 
use warnings; 

local $/ = "\n\n"; 
my $count = 0; 

while (my $chunk = <>) { 
    open (my $output, '>', "filename_".$count++) or die $!; 
    print {$output} $chunk; 
    close ($output); 
} 

Просто так. <> - это «волшебный» дескриптор файла, в котором он считывает данные с каналами или из файлов, указанных в командной строке (открывает их и читает их). Это похоже на то, как работают sed или grep.

Это может быть сведено к одной гильзе:

perl -00 -pe 'open ($out, '>', "filename_".++$n); select $out;' yourfilename_here 
+0

-00? Ну, это что-то новое. Но я стараюсь избегать одного лайнера :) –

+0

Обычно я, но когда мы участвуем в гонке 'awk', я пытаюсь включить их для сравнения. (Но, насколько это возможно, после некоторого кода, который более четко иллюстрирует). – Sobrique

+0

Спасибо! Это было! Однако при первом запуске этой команды был приведен тот же сценарий, что и в других сценариях. Причина, по-видимому, заключалась в том, что мои файлы входных данных (каждая из них длиной 4-8 М) имели неправильные разделители строк или что-то неактивное. Всякий раз, когда я открывал их в любом текстовом редакторе, они выглядели бы прекрасно. Но запуск этой команды привел к созданию одного файла, идентичного входному файлу. Но после того, как я скопировал (ugh) каждый набор данных на пустую страницу в текстовом редакторе и ударил save, размер их файлов немного изменился бы (например, 1M в файле 150 МБ), и после этого эта команда работала нормально. –

Смежные вопросы