嗨,我有一个这样的文件:
#0
0:()
1b:cg*b
1c
0:cg
xe
#4
0:()
0b:cg*b
xc
0:cg
1e
#8
0:()
0b:cg*b
xc
0:cg
xe
#12
1b:cg*b
xc
0:cg
0e
#16
xb:cg*b
1c
xe
#20
1:()
xb:cg*b
xc
1:cg
1e
#24
x:()
xb:cg*b
xc
xe
#28
0:()
1b:cg*b
0c
x:cg
0e
#29
0:()
0b:cg*b
1c
x:cg
xe
#32
0:()
1b:cg*b
其中#0
表示时间 0 ,#8
表示时间 8 等。现在我想根据给定的时间范围(如 2 到 30)打印该文件的部分(我想手动输入)。
在此文件中,时间 2 和 30 不存在,因此输出应该是从下一次 2 之后的时间 (#4) 到下一次 30 之后的时间 (#32) 之前的行(结果 temp1 = 第 7 行到 50 行)
temp1 输出应该是这样的:
#4
0:()
0bd*b
xc
0:cg
1e
#8
0:()
0bd*b
xc
0:cg
xe
#12
1bd*b
xc
0:cg
0e
#16
xbd*b
1c
xe
#20
1:()
xbd*b
xc
1:cg
1e
#24
x:()
xbd*b
xc
xe
#28
0:()
1bd*b
0c
x:cg
0e
#29
0:()
0bd*b
1c
x:cg
xe
这里 :() 、 bd*b 、 c 、 :cg 、 e 是第 2 列第一个字符后的字符串。 0 、 1 、 x 是第一个字符
现在 temp2 输出应该是这样的:
4 8 12 16 20 24 28 29
:() 0 0 - - 1 x 0 0
b:cg*b 0 0 1 x x x 1 0
c x x x 1 x x 0 1
:cg 0 0 0 - 1 - x x
e 1 x 0 x 1 x 0 x
现在我必须数数。 temp2 第 1 列中每个条目的 x 输出其规则:
- 只考虑 x 之前有 0 或 1
- 不要计算 x 之前还有另一个 x
- 如果 ax 出现在时间范围的开始处,则对其进行计数
- 如果 temp2 输出中存在除 0,1,x 之外的任何其他字符,则应忽略此字符。
所以,最终的输出应该是这样的:
name count x
:() 1 x
b:cg*b 1 x
c 2 x
:cg 1 x
e 4 x
注意:无论如何,我只想要最终输出,我不需要保留中间临时输出文件,但如果保留临时文件,那么这对我来说将是一个优势。显然,如果输入文件中存在任何空行,我不希望任何输出文件中出现任何空行,则应将其删除)
我是脚本编写新手,我编写了一个很长的 tcl 脚本,但它的运行时间很长,所以我想要一个 awk 或 sed 解决方案。
答案1
这个 Perl 脚本将一次性完成您想要的操作:
#!/usr/bin/env perl
use strict;
use Getopt::Std;
## This hash will hold the options
my %opts;
## Read the options
getopts('t:s:e:',\%opts) || do { print "Invalid option\n"; exit(1); };
## Keep the temp file if the script is run
## with -t
my $keep_temp_file=$opts{t}||undef;
## The temp file's file handle
my $tmp;
## The temp file
my $temp_file=`mktemp`;
chomp($temp_file);
## Read the time range
my $start=$opts{s}||undef;
my $end=$opts{e}||undef;
## Open the input file
open($tmp,'<',"$ARGV[0]")||
die("Need an input file as the 1st argument: $!\n");
my ($time,$want);
my (%data,%letters);
## Read the input file
line:while (<$tmp>) {
## skip blank lines
next if /^\s*$/;
## remove trailing newlines
chomp;
## Is this line one of the start times?
if (/^#(\d+)/) {
if ($1>=$start && $1<=$end) {
$time=$1;
$want=1;
} elsif ($1>=$end) {
$want=0;
last line;
}
}
## If we want this line, save it in
## the %data hash.
if ($want==1) {
## Skip if this line is the one that has the time
## definition.
next if /^#/;
## Get the two characters of the line
/^(.)(.+)/;
$data{$time}{$2}=$1;
## Save each letter seen
$letters{$2}++;
}
}
## Once the file has been processed, create
## the temp file.
open($tmp,'>',$temp_file)||
die("Could not open temp file $temp_file for writing: $!\n");
my @times=sort {$a <=> $b } keys(%data);
print $tmp " ";
printf $tmp "%6s", "$_" for @times;
print $tmp "\n";
foreach my $letter (sort keys(%letters)) {
print $tmp "$letter " ;
foreach my $time (@times) {
defined $data{$time}{$letter} ?
printf $tmp "%6s","$data{$time}{$letter} " : printf $tmp "%6s","- ";
}
print $tmp "\n";
}
close($tmp);
## Process the tmp file to get your desired output
open(my $fh,'<',"$temp_file")||
die("Could not open temp file $temp_file for reading: $!\n");
## Print the header
printf "%-7s%6s%10s\n",'name', 'count', 'x';
while (<$fh>) {
## Skip first line
next if $.==1;
## Collect the columns
my @foo=split(/\s+/);
## get the letter
my $let=shift(@foo);
my $c=0;
## Check if the first one is an x
$c++ if $foo[0] eq 'x';
## Check the rest
for (my $i=1;$i<=$#foo;$i++) {
## Get the previous position. This is complicated
## since you want to ignore the non [01x] characters
my $prev="";
for (my $k=$i-1; $k>-1; $k--) {
if ($foo[$k]=~/^[01x]$/) {
$prev=$foo[$k];
last;
}
}
## If this is an x, increment c if
## the previous character was 0 or 1
if ($foo[$i] eq 'x' && ($prev=~/^[01]$/ || $prev=~/^$/)) {
$c++;
}
}
printf "%-7s%6s%10s\n", $let,$c,"x";
}
## If we want to keep the temp file, copy
## it to the file name given.
if ($keep_temp_file) {
system("cp $temp_file $keep_temp_file");
}
## else, delete it
else {
unlink($temp_file);
}
如果将其另存为foo.pl
,则可以像这样运行:
foo.pl -s 2 -e 30 -t 2-30.temp file
设置-s
开始时间,设置-e
结束时间。如果您希望保留临时文件,请为其指定一个带有-t
.如果没有-t
,临时文件将被删除。
在你的例子中,它会产生:
$ perl foo.pl -s 2 -e 30 -t aa file2
name count x
:() 1 x
:cg 1 x
b:cg*b 1 x
c 2 x
e 4 x
我回答这个问题是因为这是一个有趣的问题,而你是新来的。但是,请注意,我们不是脚本编写服务。要求如此复杂的解决方案的问题是题外话。我们很乐意帮助您解决特定问题,但我们(通常)不会为您编写整个脚本。
下次,开始写一些东西并将你面临的问题分开。问一个具体的对每个问题提出一个问题,您可以这样构建您的脚本。