-3

Hi I have a file like this :

#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

Where #0 means at time 0 , #8 means at time 8 & so on. Now I want to print the portion of this file based on a given time range like 2 to 30 (I want to enter it manually).

Here in this file time 2 & 30 do not exist so the output should be from the next time after 2 (#4) till the line before the next time after 30 (#32) (result temp1 = line 7 to 50)

temp1 output should be like this :

#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

here :() , bd*b , c , :cg , e are the strings after first character of column 2. And 0 , 1 , x are the first character

now temp2 output should be like this:

        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

Now I have to count the no. of x for each entry in column 1 of the temp2 output the rule for it:

  1. only consider x before which there is 0 or 1
  2. don't count x before which there is another x
  3. if a x is present at the starting of time range then count it
  4. if somehow there is any other character other than 0,1,x in temp2 output than it should ignore this.

So, the final output should be like this :

name     count x
:()      1     x
b:cg*b   1     x
c        2     x
:cg      1     x
e        4     x

Note : I just want the final output anyhow, I don't need to keep the intermediate temp output file, but if the temp file will be kept then this will be an advantage for me. Obviously I don't want any blank lines in any output file if any blank line is present in the input file, it should be removed)

I am new to scripting , I wrote a long tcl script but its run time is very long so I want an awk or sed solution.

closed as too broad by terdon, derobert, Ramesh, slm, jasonwryan May 21 '14 at 20:49

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • I removed the line numbers from your example. Please always show your exact input files. – terdon May 21 '14 at 14:21
  • 6
    OK, please never do this again. I just spent a good half hour trying to answer you and now you show us a completely different file format. You need to show us the exact format of data you are dealing with. Also, we're not a script writing service. We want specific questions that can be answered with specific solutions. Not "give me a script that does my work for me". – terdon May 21 '14 at 17:43
  • 1
    That is one hell of a huge difference! Especially if they can contain special characters, that basically changes everything. Look, please just give us a minimal sample file and the exact output you would want from it. What's the point of showing us something that has no relation to the output produced? – terdon May 21 '14 at 18:00
  • 2
    I'm sorry but you're just not understanding. I will vote to close this now. You keep editing with the wrong output. If you're not willing to put in the effort to even give a correct sample, why would we be willing to help you do it? Please read the help center to understand what this site is about. We're here to answer your questions about UNix & Linux, not to write scripts for you. Perhaps you could ask here: rentacoder.ws. – terdon May 21 '14 at 18:16
  • 3
    No, please don't. Break this into small pieces, and ask a question about each specific problem you will need to overcome to solve it. We. Will. Not. Just. Write. Your. 100line script. For. You. – terdon May 21 '14 at 18:19
6

This Perl script will do what you want in one go:

#!/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);
}

If you save it as foo.pl, you can run it like this:

foo.pl -s 2 -e 30 -t 2-30.temp file 

The -s sets the start time, the -e is the end time. If you want the temp file to be kept, give a name for it with -t. Without -t, the temp file will be deleted.

On your example, it produces:

$ 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

I answered this because it was an interesting problem and you're new here. However, please note that we are not a script writing service. Questions asking for such complex solutions are off topic. We're happy to help you get around a specific problem but we (normally) will not write the whole script for you.

Next time, start writing something and separate the problems you face. Ask a specific question for each problem and you can build your script up that way.

Not the answer you're looking for? Browse other questions tagged or ask your own question.