안녕하세요 다음과 같은 파일이 있습니다.
#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 = line 7 to)여야 합니다. 50 OK)
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는 다음 규칙을 출력합니다.
- 앞에 0이나 1이 오는 x만 고려하세요.
- 앞에 다른 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
이 질문에 답하는 이유는 흥미로운 질문이고 귀하가 여기에 처음 왔기 때문입니다. 그러나 우리는 스크립팅 서비스가 아니라는 점에 유의하십시오. 이렇게 복잡한 솔루션이 필요한 질문은 요점을 벗어났습니다. 우리는 귀하의 특정 문제를 해결하는 데 기꺼이 도움을 드리지만 (보통) 귀하를 위해 전체 스크립트를 작성하지는 않습니다.
다음에는 뭔가 쓰기 시작하고 직면한 문제를 분리하세요. 하나 물어보세요특정한각 질문에 대해 질문을 하면 이런 식으로 스크립트를 구성할 수 있습니다.