#linux #bash #sed #grep
#linux #bash #sed #grep
Вопрос:
У меня есть приведенный ниже исходный файл (~ 10 ГБ), и мне нужно разделить на несколько небольших файлов (<100 МБ каждый), и каждый файл должен иметь одинаковую запись заголовка. Сложность в том, что я не могу просто разделить файл на любую случайную строку, используя какую-либо команду split . Записи, принадлежащие агенту, не должны разделяться на несколько файлов. Для простоты я показываю здесь только 2 агента (в реальном файле их тысячи).
Inout.csv
Src,AgentNum,PhoneNum
DWH,Agent_1234,phone1
NULL,NULL,phone2
NULL,NULL,phone3
DWH,Agent_5678,phone1
NULL,NULL,phone2
NULL,NULL,phone3
DWH,Agent_9999,phone1
NULL,NULL,phone2
NULL,NULL,phone3
Output1.csv
Src,AgentNum,PhoneNum
DWH,Agent_1234,phone1
NULL,NULL,phone2
NULL,NULL,phone3
Output2.csv
Src,AgentNum,PhoneNum
DWH,Agent_5678,phone1
NULL,NULL,phone2
NULL,NULL,phone3
DWH,Agent_9999,phone1
NULL,NULL,phone2
NULL,NULL,phone3
#!/bin/bash
#Calculate filesize in bytes
FileSizeBytes=`du -b $FileName | cut -f1`
#Check for the file size
if [[ $FileSizeBytes -gt 100000000 ]]
then
echo "Filesize is greater than 100MB"
NoOfLines=`wc -l < $FileName`
AvgLineSize=$((FileSizeBytes / NoOfLines))
LineCountInEachFile=$((100000000 / AvgLineSize))
#Section for splitting the files
else
echo "Filesize is already less than 100MB. No splitting needed"
exit 0
fi
Я новичок в UNIX, но пробую этот скрипт bash самостоятельно и вроде как застрял при разделении файлов. Я не ожидаю, что кто-нибудь даст мне полный сценарий, я ищу какой-либо простой подход / рекомендацию, возможно, используя другие простые альтернативы, такие как sed или тому подобное. Заранее большое спасибо!
Комментарии:
1. Доступен ли для вас perl? Если нет, вы можете попробовать awk .
2. На данный момент я ограничен использованием только сценария оболочки в моем текущем проекте. Но если у вас есть решение pearl, я могу попробовать наверняка. Спасибо!
Ответ №1:
Вот примерное представление о том, как это сделать в Perl. Пожалуйста, измените регулярное выражение, если оно не совсем соответствует вашим фактическим данным. Я тестировал его только на ваших фиктивных данных.
#!/usr/bin/perl -w
my $l=<>; chomp($l); my $header=$l;
my $agent=""; my $fh;
while ($l=<>) {
chomp($l);
if ($l=~m/^s*[^,] ,(Agent_d ),[^,] /) {
$agent="$1";
open($fh,">","${agent}.txt") or die "$!";
print $fh $header."n";
}
print $fh $l."n";
}
Используйте его следующим образом:
./perlscript.pl < inputfile.txt
Если у вас нет perl (проверьте наличие perl в /usr/bin/perl или в каком-либо другом подобном месте), я попытаюсь создать awk-скрипт. Дайте мне знать, если вы обнаружите проблемы, возникающие в приведенном выше скрипте.
В ответ на ваш обновленный запрос о том, что вы хотите разделить файл только с каждым выходным файлом размером менее 100 МБ, без разделения записей агента на два файла, и что этот заголовок печатается в каждом выходном файле, вот примерное представление о том, как вы можете это сделать. Это не приводит к точному вырезанию (потому что вам нужно будет вычислить перед записью). Если вы установите для $maxfilesize значение, подобное 95*1024*1024 или 99*1024*1024 , это должно позволить вам иметь файл размером менее 100 МБ (например, если максимальный размер записей агента составляет менее 5 МБ, то установите значение $maxfilesize равным 95* 1024 * 1024)
#!/usr/bin/perl -w
# Max file size, approximately in bytes
#
# For 99MB make it as 99*1024*1024
#
my $maxfilesize=95*1024*1024;
#my $maxfilesize=400;
my $l=<>; chomp($l); my $header=$l;
my $fh;
my $filecounter=0;
my $filename="";
my $filesize=1000000000000; # big dummy size for first iteration
while ($l=<>) {
chomp($l);
if ($l=~m/^s*[^,] ,Agent_d ,[^,] /) {
if ($filesize>$maxfilesize) {
print "FileSize: $filesizen";
$filecounter ; $filename=sprintf("outfile_d",$filecounter);
print "Opening New File: $filenamen";
open($fh,">","${filename}.txt") or die "$!";
print $fh $header."n";
$filesize=length($header);
}
}
print $fh $l."n";
$filesize =length($l);
print "FileSize: $filesizen";
}
Если вы хотите более точные сокращения, чем это, я обновлю его, буферизую данные перед печатью.
Комментарии:
1. Спасибо за сценарий pearl! Если я правильно понимаю, я думаю, что скрипт разбивает файл на разные файлы для каждого агента (по одному файлу для каждого агента). Но в моем требовании каждый выходной файл может содержать сотни агентов, если он меньше 100 МБ. Я еще не пробовал скрипт, поэтому извините, если я все понял неправильно 🙂
2. Я вижу. Итак, вы просто хотите иметь строку заголовка, несколько тысяч строк в каждом выходном файле (размером менее 100 МБ)?
3. ДА. Пока размер каждого файла <100 МБ и записи для каждого агента не будут перекрываться между файлами (разделение должно происходить в конце всех записей для агента, а не случайным образом между ними). Спасибо за ваш быстрый ответ.
Ответ №2:
Шаг 1. Сохраните заголовок
Шаг 2. создайте переменную «content» в temp-сохраните то, что программа собирается прочитать
Шаг 3. начните читать следующие строки на python:
if line.startswith("DWH"):
if content != "":
#if the content.len() reaches your predefined size, output_your_header content here and reinitiate content by 'content = ""'
#else, content.len() is still under size limit, keep adding the new agent to content by doing 'content = line'
else:
content = line
Комментарии:
1. Спасибо @dgg32, но я ищу решение в оболочке UNIX.