Разделение большого файла txt на 200 меньших txt файлов в регулярном выражении с использованием оболочки script в BASH
Привет, ребята, я надеюсь, что тема достаточно ясна, я не нашел ничего конкретного об этом в ранее запрошенном бинде. Я пробовал реализовать это в Perl или Python, но я думаю, что я, возможно, слишком стараюсь.
Есть ли простая команда/конвейер оболочки, которая будет разбивать мой файл 4 МБ .txt на отдельные .txt файлы на основе начального и конечного регулярных выражений?
Я предоставляю короткий образец файла ниже.., чтобы вы могли видеть, что каждая "история" начинается с фразы "X of XXX DOCUMENTS", которую можно использовать для разбиения файла.
Я думаю, что это должно быть легко, и я был бы удивлен, если bash не сможет этого сделать - быстрее, чем Perl/Py.
Вот он:
1 of 999 DOCUMENTS
Copyright 2011 Virginian-Pilot Companies LLC
All Rights Reserved
The Virginian-Pilot(Norfolk, VA.)
...
3 of 999 DOCUMENTS
Copyright 2011 Canwest News Service
All Rights Reserved
Canwest News Service
...
Заранее благодарим за вашу помощь.
Росс
Ответы
Ответ 1
awk '/[0-9]+ of [0-9]+ DOCUMENTS/{g++} { print $0 > g".txt"}' file
Пользователям OSX потребуется gawk
, так как встроенный awk
приведет к ошибке, например awk: illegal statement at source line 1
Рубин (1.9 +)
#!/usr/bin/env ruby
g=1
f=File.open(g.to_s + ".txt","w")
open("file").each do |line|
if line[/\d+ of \d+ DOCUMENTS/]
f.close
g+=1
f=File.open(g.to_s + ".txt","w")
end
f.print line
end
Ответ 2
Как было предложено в других решениях, вы можете использовать csplit
для этого:
csplit csplit.test '/^\.\.\./' '{*}' && sed -i '/^\.\.\./d' xx*
Я не нашел лучшего способа избавиться от напоминающего разделителя в разделенных файлах.
Ответ 3
Насколько вы старались в Perl?
Изменить. Это более быстрый метод. Он разбивает файл и печатает файлы деталей.
use strict;
use warnings;
my $count = 1;
open (my $file, '<', 'source.txt') or die "Can't open source.txt: $!";
for (split /(?=^.*\d+[^\S\n]*of[^\S\n]*\d+[^\S\n]*DOCUMENTS)/m, join('',<$file>))
{
if ( s/^.*(\d+)\s*of\s*\d+\s*DOCUMENTS.*(\n|$)//m )
{
open (my $part, '>', "Part$1_$count.txt")
or die "Can't open Part$1_$count for output: $!";
print $part $_;
close ($part);
$count++;
}
}
close ($file);
Это метод линии за строкой:
use strict;
use warnings;
open (my $masterfile, '<', 'yourfilename.txt') or die "Can't open yourfilename.txt: $!";
my $count = 1;
my $fh;
while (<$masterfile>) {
if ( /(?<!\d)(\d+)\s*of\s*\d+\s*DOCUMENTS/ ) {
defined $fh and close ($fh);
open ($fh, '>', "Part$1_$count.txt") or die "Can't open Part$1_$count for output: $!";
$count++;
next;
}
defined $fh and print $fh $_;
}
defined $fh and close ($fh);
close ($masterfile);
Ответ 4
регулярное выражение для соответствия "X из XXX ДОКУМЕНТОВ" - это
\ d {1,3} из \d {1,3) ДОКУМЕНТЫ
чтение строки за строкой и начало записи нового файла при регулярном совпадении должно быть хорошо.
Ответ 5
Непроверенные:
base=outputfile
start=1
pattern='^[[:blank:]]*[[:digit:]]+ OF [[:digit:]]+ DOCUMENTS[[:blank:]]*$
while read -r line
do
if [[ $line =~ $pattern ]]
then
((start++))
printf -v filecount '%4d' $start
>"$base$filecount" # create an empty file named like foo0001
fi
echo "$line" >> "$base$filecount"
done