Разделение файлов на основе содержимого файла и сопоставления с образцом - PullRequest
13 голосов
/ 25 ноября 2011

Мне нужна ваша помощь в формировании TXT-файла с помощью bash / linux.Файл выглядит следующим образом, в нем всегда есть строка Rate: Sth, затем он следует с подробностями в очень специфическом формате.Я хотел бы разделить файл с одной скоростью для каждого файла.В этом примере я хотел бы иметь 3 файла, и в каждой строке есть соответствующая строка, в которой указано значение показателя Rate.

Как вы подойдете к этому?

line No. Main Text
1    Rate: GBP
2    12/01/1999,90.5911501,Validated
     .....
     .....
210  18/01/1999,90.954996,Validated
211  Rate: RMB
212  24/04/2008,132.2542,Validated
     .....
1000 25/04/2008,132.2279,Validated
1001 28/04/2008,131.69915,Validated
1002 Rate: USD
1003 21/11/11,-0.004419534,Validated

Ответы [ 6 ]

8 голосов
/ 26 ноября 2011

Это может работать для вас:

csplit -z -f 'temp' -b '%02d.txt' file /Rate/ {*}

Это создаст файлы temp00.txt, temp01.txt ...

Если вам нужна только строка Rate, то

sed -i '/Rate/!d' temp*.txt
5 голосов
/ 25 ноября 2011

Я бы сделал это в Perl:

#!/usr/bin/perl

use strict;
use warnings;

open (my $out, ">-") or die "oops";

while(<>)
{
    if (m/^Rate: (\w+)/o)
    {
        close $out and open ($out, ">$1") or die "oops";
        next;
    }

    print $out $_
}

Используйте это как

perl ./test.pl input.txt
3 голосов
/ 25 ноября 2011

Однострочник, вдохновленный ответом sehe:

>perl -pwe '
> if (/^Rate: (.+)/) { 
>    open $out, ">", "Rate_$1.txt" or die $!; 
>    select $out; 
> }' gasdata.txt

Опция -p прочитает строку и напечатает ее после оценки кода в -e.select выберет дескриптор файла по умолчанию для print.Таким образом, в основном мы просто манипулируем дескриптором файла, в зависимости от того, какой курс в данный момент является активным.

Вот код, который был отменен:

>perl -MO=Deparse -pwe 'if (/^Rate: (.+)/) { open $out, ">", "output/Rate_$1.txt" or die $!; select $out; }' gasdata.txt
BEGIN { $^W = 1; }
LINE: while (defined($_ = <ARGV>)) {
    if (/^Rate: (.+)/) {
        die $! unless open $out, '>', "output/Rate_$1.txt";
        select $out;
    }
}
continue {
    die "-p destination: $!\n" unless print $_;
}
-e syntax OK
3 голосов
/ 25 ноября 2011

(g)awk на помощь:

awk '/^Rate:/ {output_file_name=$2; getline } 
     { print $0 >> ( output_file_name ) }' INPUT_FILE

Первое правило и команда выполняется для строк, начинающихся с Rate:, и задает только имя выходного файла, затем получает следующую строку из входного файла. Затем следующая строка обрабатывается и записывается в выходной файл. После этого следующая строка обрабатывается только второй командой (записывается в выходной файл), но только если она не соответствует Rate:.

ПРИМЕЧАНИЕ: Приведенное выше решение может дать сбой, если во входном файле есть раздел с двумя непрерывными строками Rate: с, например:

... DATA ...
Rate: GBP
Rate: CHF
... DATA ...

следует сделать (при условии, что номера строк не являются частью исходного файла).

НТН

1 голос
/ 25 ноября 2011

Вы можете использовать что-то подобное в perl -

Скрипт Perl:

#!/usr/bin/perl

undef $/;
$_ = <>;
$n = 0;

for $match (split(/(?=Rate)/)) {
      open(O, '>temp' . ++$n);
      print O $match;
      close(O);
}

Выполнение:

[jaypal~/temp]$ ./spl.pl temp.file

[jaypal~/temp]$ **cat temp.file**
Line No. Main Text
1    Rate: GBP
2    12/01/1999,90.5911501,Validated
     .....
     .....
210  18/01/1999,90.954996,Validated
211  Rate: RMB
212  24/04/2008,132.2542,Validated
     .....
1000 25/04/2008,132.2279,Validated
1001 28/04/2008,131.69915,Validated
1002 Rate: USD
1003 21/11/11,-0.004419534,Validated

[jaypal~/temp]$ cat temp1
Line No. Main Text
1    

[jaypal~/temp]$ cat temp2
Rate: GBP
2    12/01/1999,90.5911501,Validated
     .....
     .....
210  18/01/1999,90.954996,Validated

211  

[jaypal~/temp]$ cat temp3
Rate: RMB
212  24/04/2008,132.2542,Validated
     .....
1000 25/04/2008,132.2279,Validated
1001 28/04/2008,131.69915,Validated

1002 [jaypal~/temp]$ cat temp4
Rate: USD
1003 21/11/11,-0.004419534,Validated
[jaypal~/temp]$ 
1 голос
/ 25 ноября 2011

Другое решение: он просто превращает ваш входной файл в скрипт и затем запускает его:

sed 's/^Rate:/cat <<EOF >/; 1!s/^cat <<EOF/EOF\n&/; $aEOF' input.txt | bash

Я предположил, что номера строк не часть файла.

...