Hi All,
I hv several files which have hundreds of lines each for example
>XYZ.abc01
NNNTCGGTNNNNNCCACACACMYACACACCCACACCCACSCARCAC
I'd like to exculde the first line beginning with ">" and then for the rest of the lines get a count for each string element. So for the above example I would like to get the following output:
A=11
C=19
G=2
M=1
N=8
R=1
S=1
T=2
Y=1
Length of XYZ.abc01=46
Can anyone enlighten on this and if there is a Perl way i'll appreciate that as I'm learning Perl
Cheers and hv a nice day
ctsgnb
April 7, 2011, 6:00am
2
I didn't try it (may require some fix) but maybe something like this
#!/bin/ksh
{ read a
while read a
do
[[ -z $a ]] && continue
b=${a#?}
c=${a%$b}
if [[ "$c" == '>' ]]
then
h=$b
continue
else
fold -w 1 <(echo $a) | sort | uniq -c | awk '{print $2"="$1}'
echo "Length of $h=${#a}"
fi
done } <infile
seems working :
# cat tst
dummy first line
>XYZ.abc01
NNNTCGGTNNNNNCCACACACMYACACACCCACACCCACSCARCAC
>XYYUIZ.abc01
NNNTCGGTCACACMYACACACCCACCACACMYACACACCCACNNNNNCCACACACMYACACACCCACACCCACSCARCAC
>XYYU.abc03
NNNTCGGTCACACMYACACACCCACCACACMYACACACCCACNCACCCACACCCACSCARCAC
>XYYUIZ.abc04
NNNTCGGTCACACMYACACACCCACCACACMYAACACACCCACACCCACSCARCAC
>XYYUIZ.abc05
NNNTCGGTCACACMYACACANNNCCACACACMYACACACCCACACCCACSCARCAC
>XYYUIZ.abc06
NNNTCGGTCACACMYACACAACACMYACACACCCACNNNNNCCACACACMYACACACCCACACCCACSCARCAC
>XYYUIZ.abc07
NNNTCGGTCACACMYACACACCACACACMYACACACCCACACCCACSCARCAC
# cat sc
#!/bin/ksh
{ read a
while read a
do
[[ -z $a ]] && continue
b=${a#?}
c=${a%$b}
if [[ "$c" == '>' ]]
then
h=$b
continue
else
fold -w 1 <(echo $a) | sort | uniq -c | awk '{print $2"="$1}'
echo "Length of $h=${#a}"
fi
done } <tst
# ksh sc
A=11
C=19
G=2
M=1
N=8
R=1
S=1
T=2
Y=1
Length of XYZ.abc01=46
A=23
C=37
G=2
M=3
N=8
R=1
S=1
T=2
Y=3
Length of XYYUIZ.abc01=80
A=18
C=31
G=2
M=2
N=4
R=1
S=1
T=2
Y=2
Length of XYYU.abc03=63
A=17
C=26
G=2
M=2
N=3
R=1
S=1
T=2
Y=2
Length of XYYUIZ.abc04=56
A=16
C=24
G=2
M=2
N=6
R=1
S=1
T=2
Y=2
Length of XYYUIZ.abc05=56
A=22
C=32
G=2
M=3
N=8
R=1
S=1
T=2
Y=3
Length of XYYUIZ.abc06=74
A=16
C=24
G=2
M=2
N=3
R=1
S=1
T=2
Y=2
Length of XYYUIZ.abc07=53
#
Try:
perl -aF// -lne 'if ($.==1){s/^>//;$n=$_}else{for $i (@F){$h{$i}++;$l++}}END{for $i (keys %h){print "$i=$h{$i}"}print "Length of $n=$l"}' file
ctsgnb
April 7, 2011, 6:24am
4
We could make the output less longer putting letter stats in one line by changing this in the previous scripts:
fold -w 1 <(echo $a) | sort | uniq -c | awk '{print $2"="$1}' | xargs
# ksh sc
A=11 C=19 G=2 M=1 N=8 R=1 S=1 T=2 Y=1
Length of XYZ.abc01=46
A=23 C=37 G=2 M=3 N=8 R=1 S=1 T=2 Y=3
Length of XYYUIZ.abc01=80
A=18 C=31 G=2 M=2 N=4 R=1 S=1 T=2 Y=2
Length of XYYU.abc03=63
A=17 C=26 G=2 M=2 N=3 R=1 S=1 T=2 Y=2
Length of XYYUIZ.abc04=56
A=16 C=24 G=2 M=2 N=6 R=1 S=1 T=2 Y=2
Length of XYYUIZ.abc05=56
A=22 C=32 G=2 M=3 N=8 R=1 S=1 T=2 Y=3
Length of XYYUIZ.abc06=74
A=16 C=24 G=2 M=2 N=3 R=1 S=1 T=2 Y=2
Length of XYYUIZ.abc07=53
tene
April 7, 2011, 6:26am
5
Create an awk script awk_cmd
#!/bin/awk
{
if($0~/^$/)
next;
if($0~/^>/)
{
label=$0;
next;
}
for(x=1;x<=length($0);x++)
{arr[substr($0,x,1)]++
}
for (i in arr)
{
print i":"arr;sum+=arr;arr=0
}
print "Length of "label"="sum;sum=0
}
Execute :
awk -f awk_cmd inputfile
kurumi
April 7, 2011, 6:27am
6
Ruby(1.9+)
$ ruby -ne 'next if $.==1;$_.chomp.split(//).group_by{|x|x}.each{|x,y| puts "#{x}:#{y.count}"}' file
N:8
T:2
C:19
G:2
A:11
M:1
Y:1
S:1
R:1
@ctsgnb
Thank you !
@Bartus
Thanks a lot for the Perl version. Could you please explain the use of -F switch and // after that ?
Cheers
As you remember from previous Perl one-liners, -a is splitting each line into @F array, using space as default delimiter. To specify other delimiter we use -F option with regular expression following it (as with split function). If we use empty regular expression: // , each line will be split into separate characters, so each of the line's characters will be contained in separate @F field.
ctsgnb
April 7, 2011, 6:54am
9
you can add
[[ -z $a ]] && continue
just after the "do" line so that empty lines will not be a problem