Linux 基于文件内容和模式匹配拆分文件
我需要你的帮助,用bash/linux格式化一个txt文件。该文件如下所示,它始终有一行名为Rate:Sth,然后以非常具体的格式显示细节。我想把这个文件分成两部分,每个文件一个费率。在本例中,我希望有3个文件,每个文件都有相应的行,表示速率值是多少 你将如何处理这个问题Linux 基于文件内容和模式匹配拆分文件,linux,perl,bash,pattern-matching,Linux,Perl,Bash,Pattern Matching,我需要你的帮助,用bash/linux格式化一个txt文件。该文件如下所示,它始终有一行名为Rate:Sth,然后以非常具体的格式显示细节。我想把这个文件分成两部分,每个文件一个费率。在本例中,我希望有3个文件,每个文件都有相应的行,表示速率值是多少 你将如何处理这个问题 line No. Main Text 1 Rate: GBP 2 12/01/1999,90.5911501,Validated ..... ..... 210 18/01/1999,90.9
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
我会用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 $_
}
另一种解决方案:它只是将您的输入文件制作成脚本,然后运行它:
sed 's/^Rate:/cat <<EOF >/; 1!s/^cat <<EOF/EOF\n&/; $aEOF' input.txt | bash
sed的/^Rate:/cat您可以在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]$
(g)awk
救援:
awk '/^Rate:/ {output_file_name=$2; getline }
{ print $0 >> ( output_file_name ) }' INPUT_FILE
第一条规则和命令对以Rate:
开头的行执行,只设置输出文件名,然后从输入文件中获取下一行。然后处理下一行并将其写入输出文件。之后,下一行仅由第二个命令(写入输出文件)处理,但前提是它与Rate:
不匹配
注意:如果输入文件中有两行连续的Rate:
s,则上述解决方案可能会失败,如下所示:
... DATA ...
Rate: GBP
Rate: CHF
... DATA ...
应该这样做(假设行号不是原始文件的一部分)
HTH一句话的灵感来源于sehe的回答:
>perl -pwe '
> if (/^Rate: (.+)/) {
> open $out, ">", "Rate_$1.txt" or die $!;
> select $out;
> }' gasdata.txt
计算-e
中的代码后,-p
选项将读取一行并打印它<代码>选择
将为打印
选择默认文件句柄。因此,基本上,我们所做的只是简单地改变文件句柄,这取决于当前的活动速率
下面是被分解的代码:
>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
>perl-MO=Deparse-pwe'if(/^Rate:(.+)/){open$out,“>”、“output/Rate_$1.txt”或die$!;选择$out;}'gasdata.txt
开始{$^W=1;}
行:while(已定义($\u=)){
如果(/^费率:(.+)/){
die$!除非打开$out,“>”,“输出/速率_$1.txt”;
选择$out;
}
}
继续{
模具“-p目的地:$!\n”,除非打印$;
}
-e语法正常
这可能适合您:
csplit -z -f 'temp' -b '%02d.txt' file /Rate/ {*}
这将生成文件temp00.txt、temp01.txt
如果您只需要Rate
行,那么
sed -i '/Rate/!d' temp*.txt
聪明的先开,让循环简洁。非常好。+1代表鼓舞人心的答案。请参阅我的答案,了解您想法的一行代码版本。只是为了澄清行号不是文件的一部分。我还希望输出文件包含速率:**Line。这不会在匹配模式后只得到一行吗?感谢Zsolt的解释。不知道为什么,但我仍然有运行一个班轮的问题。
print$0>>输出文件名不应该有“
围绕输出文件名
我喜欢这个解决方案!尤其是使用速率文本命名文件的方式。一个小的诡辩,但可能会节省一些头发-这里的文档将插入变量等默认情况下s/^Rate:/cat一个小的调整,您也可以有Rate…
行<代码>/^速率:/{h;s//…/;G}代码>
sed -i '/Rate/!d' temp*.txt