unix -- get number of business days - date

I'm using AIX with the ksh. I'm trying to calculate the number of business days in a month. I was trying to use AWK but I'm hung up now.
Here's what I've got so far:
cal | awk '{print $2, $3, $4, $5, $6} | awk 'NR > 2'
Here's the normal output (for current date/time) for cal:
April 2014
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Here's what I'm getting with that script:
2 3 4 5
7 8 9 10 11
14 15 16 17 18
21 22 23 24 25
28 29 30
My plan is to, in the end, read these lines into a c program and output the total weekdays (right now we're not worried about holidays on normal business days).
As you can see here, since the 3rd line of output is only 5 columns itself, it's dropping the 1st business day of that week. Maybe I'm going about this whole thing wrong -- if there's another way to do this on the Unix operating system or through C: I have no sentimental attachment to "cal" and "awk" (not yet anyway).

This can make it:
cal -h | cut -c 4-17 | tail -n +3 | wc -w
Explanation
cal shows line on columns of 4 characters. -h turns off highlighting of today.
April 2014
Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Since Sunday is first column and Saturday the last one, it is a matter of extracting the numbers in between character 4 and 17:
$ cal -h | cut -c 4-17
April 2014
Mo Tu We Th Fr
1 2 3 4
7 8 9 10 11
14 15 16 17 18
21 22 23 24 25
28 29 30
And then remove the two first lines:
$ cal -h | cut -c 4-17 | tail -n +3
1 2 3 4
7 8 9 10 11
14 15 16 17 18
21 22 23 24 25
28 29 30
And then count the number of words:
$ cal -h | cut -c 4-17 | tail -n +3 | wc -w
22

To calculate working days of month, until today:
TODAY=\`date +%d\`
WDAYS=\`ncal -h | grep -vE "^S|^ |^$" | sed "s/[[:alpha:]]//g" | fmt -w 1 | sort -n | grep $TODAY -B 33 | wc -l\`
echo $WDAYS

Related

diff -y usage of |'s vs. >'s and <'s in the output

I have two files:
cat test1
1
3
5
11
13
17
19
21
22
23
29
30
32
33
34
39
and
cat test2
2
4
6
10
12
20
21
22
23
24
29
30
31
32
34
49
When I diff them, I get:
diff -y test1 test2
1 | 2
3 | 4
5 | 6
11 | 10
13 | 12
17 | 20
19 <
21 21
22 22
23 23
> 24
29 29
30 30
> 31
32 32
33 <
34 34
39 | 49
The meaning and behavior of when diff -y produces "|" instead of "<" or ">" has proven very difficult to dig up in spite of googling. I understand what it means, I think (i.e. "19 <" instead of "19 | 21" b/c 21 is present later in file1 to match up with the aforementioned 21 in file2) but it strikes me as obtuse b/c the output of a given line is being influenced by subsequent ones, and depending on output formatting there is nothing indicating that the command is doing this or why.
Is there a way to suppress this behavior or make it more transparent?
I want to suppress common lines in my output, and the problem is without the common lines, this next output is very confusing (for reasons I outlined above - the common lines give context as to "why are some of these |'s and the others are >'s or <'s?", so looking at the below output there's seemingly no answer to that question):
diff -y --suppress-common-lines test1 test2
1 | 2
3 | 4
5 | 6
11 | 10
13 | 12
17 | 20
19 <
> 24
> 31
33 <
39 | 49
I'd basically like it to be either |'s -OR- all <'s and >'s

how can I replace letter to certain number [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have a huge data like the following
NDDDDTSVCLGTRQCSWFAGCTNRTWNSSA 0
VCLGTRQCSWFAGCTNRTWNSSAVPLIGLP 0
LTWSGNDTCLYSCQNQTKGLLYQLFRNLFC 0
CQNQTKGLLYQLFRNLFCSYGLTEAHGKWR 0
ITNDKGHDGHRTPTWWLTGSNLTLSVNNSG 0
GHRTPTWWLTGSNLTLSVNNSGLFFLCGNG 0
FLCGNGVYKGFPPKWSGRCGLGYLVPSLTR 0
KGFPPKWSGRCGLGYLVPSLTRYLTLNASQ 0
QSVCMECQGHGERISPKDRCKSCNGRKIVR 1
I want to use the following key to replace the letter with numbers
A 1
R 2
N 3
D 4
B 5
C 6
E 7
Q 8
Z 9
G 10
H 11
I 12
L 13
K 14
M 15
F 16
P 17
S 18
T 19
W 20
Y 21
V 22
at first I want to remove all the numbers close to letter and then replace the letters , so lets look at the first like
NDDDDTSVCLGTRQCSWFAGCTNRTWNSSA
will have this
3 4 4 4 4 19 18 22 6 19 13 10 19 2 8 6 18 20 16 1 10 6 19 3 2 19 20 3 18 18 1
and for the rest of lines the same as many lines as I have
perl -e'
use autodie;
my %charmap = (
A => 1, R => 2, N => 3, D => 4, B => 5, C => 6, E => 7, Q => 8,
Z => 9, G => 10, H => 11, I => 12, L => 13, K => 14, M => 15, F => 16,
P => 17, S => 18, T => 19, W => 20, Y => 21, V => 22,
);
while (<>) {
s{(.)}{ ($charmap{$1} // $1) . " " }ge;
print;
}
' file
Or just
perl -pe'
BEGIN { #charmap{ split //, "ARNDBCEQZGHILKMFPSTWYV" } = 1..22 }
s{(.)}{ ($charmap{$1} // $1) . " " }ge;
' file
With any awk in any shell on any UNIX box:
$ cat tst.awk
BEGIN {
chars = "ARNDBCEQZGHILKMFPSTWYV"
for (i=1; i<=length(chars); i++) {
char = substr(chars,i,1)
map[char] = i
}
}
{
out = ""
chars = $1
for (i=1; i<=length(chars); i++) {
char = substr(chars,i,1)
out = (out == "" ? "" : out " ") (char in map ? map[char] : char)
}
print out
}
$ awk -f tst.awk file
3 4 4 4 4 19 18 22 6 13 10 19 2 8 6 18 20 16 1 10 6 19 3 2 19 20 3 18 18 1
22 6 13 10 19 2 8 6 18 20 16 1 10 6 19 3 2 19 20 3 18 18 1 22 17 13 12 10 13 17
13 19 20 18 10 3 4 19 6 13 21 18 6 8 3 8 19 14 10 13 13 21 8 13 16 2 3 13 16 6
6 8 3 8 19 14 10 13 13 21 8 13 16 2 3 13 16 6 18 21 10 13 19 7 1 11 10 14 20 2
12 19 3 4 14 10 11 4 10 11 2 19 17 19 20 20 13 19 10 18 3 13 19 13 18 22 3 3 18 10
10 11 2 19 17 19 20 20 13 19 10 18 3 13 19 13 18 22 3 3 18 10 13 16 16 13 6 10 3 10
16 13 6 10 3 10 22 21 14 10 16 17 17 14 20 18 10 2 6 10 13 10 21 13 22 17 18 13 19 2
14 10 16 17 17 14 20 18 10 2 6 10 13 10 21 13 22 17 18 13 19 2 21 13 19 13 3 1 18 8
8 18 22 6 15 7 6 8 10 11 10 7 2 12 18 17 14 4 2 6 14 18 6 3 10 2 14 12 22 2
Alternative Perl solution:
#!/usr/bin/perl
use strict;
use warnings;
my %key = (
A => 1, R => 2, N => 3, D => 4, B => 5,
C => 6, E => 7, Q => 8, Z => 9, G => 10,
H => 11, I => 12, L => 13, K => 14, M => 15,
F => 16, P => 17, S => 18, T => 19, W => 20,
Y => 21, V => 22,
);
while (<STDIN>) {
my($text) = /^(\w+)/;
print join(' ',
map { $key{$_} }
split(//, $text)
), "\n";
}
exit 0;
Output with your given text:
$ perl dummy.pl <dummy.txt
3 4 4 4 4 19 18 22 6 13 10 19 2 8 6 18 20 16 1 10 6 19 3 2 19 20 3 18 18 1
22 6 13 10 19 2 8 6 18 20 16 1 10 6 19 3 2 19 20 3 18 18 1 22 17 13 12 10 13 17
13 19 20 18 10 3 4 19 6 13 21 18 6 8 3 8 19 14 10 13 13 21 8 13 16 2 3 13 16 6
6 8 3 8 19 14 10 13 13 21 8 13 16 2 3 13 16 6 18 21 10 13 19 7 1 11 10 14 20 2
12 19 3 4 14 10 11 4 10 11 2 19 17 19 20 20 13 19 10 18 3 13 19 13 18 22 3 3 18 10
10 11 2 19 17 19 20 20 13 19 10 18 3 13 19 13 18 22 3 3 18 10 13 16 16 13 6 10 3 10
16 13 6 10 3 10 22 21 14 10 16 17 17 14 20 18 10 2 6 10 13 10 21 13 22 17 18 13 19 2
14 10 16 17 17 14 20 18 10 2 6 10 13 10 21 13 22 17 18 13 19 2 21 13 19 13 3 1 18 8
8 18 22 6 15 7 6 8 10 11 10 7 2 12 18 17 14 4 2 6 14 18 6 3 10 2 14 12 22 2
On second thought...
As OP wants to obfuscate clear text then the more appropriate solution IMHO should be something like this:
$ bash <dummy.txt -c "$(echo /Td6WFoAAATm1rRGBMCtAbgBIQEWAAAAAAAAACsG0SbgALcApV0AOBlKq3igoJRmX9TqJifIRDIcDLdDtNRSv+tJBsifrrsdnlllNt2qqnlz0/uBmSnlO0FTKjKH/HXplJm9LaV7kXiNp/ZWDsyVqoV8EPjIEHHkXXd6jKahyq7tcCA4NGTHp/pwmk8jith6j/dcX67QCKmL0UtZUz9BqVWefD41lbrTNazbD8IP6zMLmAVxJav51SSTHzsUqhUfqhVmLsUg8sJkgloAAAAAAOMYtQXt21WNAAHJAbgBAABTvtYRscRn+wIAAAAABFla | base64 -d | xzcat)"
3 4 4 4 4 19 18 22 6 13 10 19 2 8 6 18 20 16 1 10 6 19 3 2 19 20 3 18 18 1
22 6 13 10 19 2 8 6 18 20 16 1 10 6 19 3 2 19 20 3 18 18 1 22 17 13 12 10 13 17
13 19 20 18 10 3 4 19 6 13 21 18 6 8 3 8 19 14 10 13 13 21 8 13 16 2 3 13 16 6
6 8 3 8 19 14 10 13 13 21 8 13 16 2 3 13 16 6 18 21 10 13 19 7 1 11 10 14 20 2
12 19 3 4 14 10 11 4 10 11 2 19 17 19 20 20 13 19 10 18 3 13 19 13 18 22 3 3 18 10
10 11 2 19 17 19 20 20 13 19 10 18 3 13 19 13 18 22 3 3 18 10 13 16 16 13 6 10 3 10
16 13 6 10 3 10 22 21 14 10 16 17 17 14 20 18 10 2 6 10 13 10 21 13 22 17 18 13 19 2
14 10 16 17 17 14 20 18 10 2 6 10 13 10 21 13 22 17 18 13 19 2 21 13 19 13 3 1 18 8
8 18 22 6 15 7 6 8 10 11 10 7 2 12 18 17 14 4 2 6 14 18 6 3 10 2 14 12 22 2
another awk
$ awk 'NR==FNR {a[$1]=$2; next}
{n=length($1);
for(i=1;i<=n;i++)
printf "%s", a[substr($1,i,1)] (i==n?ORS:OFS)}' mapfile datafile
3 4 4 4 4 19 18 22 6 13 10 19 2 8 6 18 20 16 1 10 6 19 3 2 19 20 3 18 18 1
22 6 13 10 19 2 8 6 18 20 16 1 10 6 19 3 2 19 20 3 18 18 1 22 17 13 12 10 13 17
13 19 20 18 10 3 4 19 6 13 21 18 6 8 3 8 19 14 10 13 13 21 8 13 16 2 3 13 16 6
6 8 3 8 19 14 10 13 13 21 8 13 16 2 3 13 16 6 18 21 10 13 19 7 1 11 10 14 20 2
12 19 3 4 14 10 11 4 10 11 2 19 17 19 20 20 13 19 10 18 3 13 19 13 18 22 3 3 18 10
10 11 2 19 17 19 20 20 13 19 10 18 3 13 19 13 18 22 3 3 18 10 13 16 16 13 6 10 3 10
16 13 6 10 3 10 22 21 14 10 16 17 17 14 20 18 10 2 6 10 13 10 21 13 22 17 18 13 19 2
14 10 16 17 17 14 20 18 10 2 6 10 13 10 21 13 22 17 18 13 19 2 21 13 19 13 3 1 18 8
8 18 22 6 15 7 6 8 10 11 10 7 2 12 18 17 14 4 2 6 14 18 6 3 10 2 14 12 22 2
however, there is no provision of missing mappings that are not specified, i.e. if you have chars not listed on the mapfile they will be ignored.
If the goal is encryption I'll propose a different approach:
First let's generate a mapping (or encryption key)
$ key=$(printf "%s\n" {A..Z} | shuf | paste -sd' ' | tr -d ' ')
$ echo "$key"
CNYSGFRDKQTOXJVLEWBAHZPMUI
now you can encrypt/decrypt your file contents, simply
$ tr [A-Z] "$key" < datafile > file.encrypted
and to reverse
$ tr "$key" [A-Z] < file.encrypted > file.decrypted
obviously, you need to save the key.

Crystal Report Data Format Change

I have data like
Date ColumnName1 ColumnName2 ColumnName3 ColumnName4 ColumnName5
2018-04-01 1 2 3 4 5
2018-04-02 6 7 8 9 10
2018-04-03 11 12 13 14 15
2018-04-04 16 17 18 19 20
2018-04-05 21 22 23 24 25
and I want data like following
2018-04-01 2018-04-02 2018-04-03 2018-04-03 2018-04-05
1 6 11 16 21
2 7 12 17 22
3 8 13 18 23
4 9 14 19 24
5 10 15 20 25
Now what to do?

Accumulate sliding blocks into a matrix

In MATLAB, we can use im2col and col2im to transform from columns to blocks and back, for example
>> A = floor(30*rand(4,6))
A =
8 5 2 13 15 11
22 11 27 13 24 24
5 18 23 9 23 15
20 23 14 15 19 10
>> B = im2col(A,[2 2],'distinct')
B =
8 5 2 23 15 23
22 20 27 14 24 19
5 18 13 9 11 15
11 23 13 15 24 10
>> col2im(B,[2 2],[4,6],'distinct')
ans =
8 5 2 13 15 11
22 11 27 13 24 24
5 18 23 9 23 15
20 23 14 15 19 10
my question is that: after using im2col with sliding mode
>> B = im2col(A,[2 2],'sliding')
B =
8 22 5 5 11 18 2 27 23 13 13 9 15 24 23
22 5 20 11 18 23 27 23 14 13 9 15 24 23 19
5 11 18 2 27 23 13 13 9 15 24 23 11 24 15
11 18 23 27 23 14 13 9 15 24 23 19 24 15 10
I wish to get a 4-by-6 matrix C from B(without knowing A) that the value at each site equals the original value multiple the times of sampling.
In other word, C(1,1)=A(1,1), C(1,2)=A(1,2)*2, C(2,2) = A(2,2)*4
Though we can easily implement with a for-loop, but the efficiency is critically low. So how to vectorize the implementation?
If I'm understanding correctly, you're desired output is
C = [ 8 10 4 26 30 11
44 44 108 52 96 48
10 72 92 36 92 30
20 46 28 30 38 10 ]
which I got by computing C = A.*S where
S = [ 1 2 2 2 2 1
2 4 4 4 4 2
2 4 4 4 4 2
1 2 2 2 2 1 ]_
The entries in S represent how many sliding blocks each entry is a member of.
I believe your question boils down to how to construct the matrix S.
Solution:
S = min(min(1:M,M:-1:1),x)'*min(min(1:N,N:-1:1),y)
C = A.*S
where A is size M-by-N, and your sliding block is size x-by-y.
Explanation:
In the given example, M=4, N=6, x=2, and y=2.
Notice the solution S can be written as the outer product of two vectors:
S = [1;2;2;1] * [1,2,2,2,2,1]
We construct each of these two vectors using the values of M,N,x,y:
min(1:M,M:-1:1)' == min(1:4,4:-1:1)'
== min([1,2,3,4], [4,3,2,1])'
== [1,2,2,1]'
== [1;2;2;1]
In this case, the extra min(...,x) does nothing since all entries are already <=x.
min(1:N,N:-1:1) == min(1:6,6:-1:1)
== min([1,2,3,4,5,6],[6,5,4,3,2,1])
== [1,2,3,3,2,1]
This time the extra min(...,y) does matter.
min(min(1:N,N:-1:1),y) == min([1,2,3,3,2,1],y)
== min([1,2,3,3,2,1],2)
== [1,2,2,2,2,1]

In matlab, how to calculate elapsed time between rows in a matrix

I have a 21128x9 matrix in the following format:
x = ['Participant No.' 'yyyy' 'mm' 'dd' 'HH' 'MM' 'SS' 'question No.' 'response']
e.g.
x =
Columns 1 through 5
18 2011 10 26 15
18 2011 10 26 15
18 2011 10 26 15
18 2011 10 26 15
18 2011 10 26 15
19 2011 10 31 13
19 2011 10 31 13
19 2011 10 31 13
19 2011 10 31 13
19 2011 10 31 13
Columns 6 through 9
42 33 27 4
42 39 17 2
42 45 52 2
42 47 45 3
42 50 12 3
6 5 36 1
6 20 27 4
6 22 34 5
6 33 43 3
6 42 42 1
where columns 2-7 are date vectors.
The data are sorted by date/time.
I'd like to calculate the time taken to answer each question for each participant - i.e. the time elapsed between row 1 and 2, 2 and 3, 3 and 4, 4 and 5, and then 6 and 7, 7 and 8 etc. - to end up with a matrix, sorted by participant number, where I can then work out the mean time taken per question.
I've tried using the etime function, but to no avail.
EDIT: With regards to etime, just to see if it would work in practice, I tried to write:
etime(x(2,5:7),x(1,5:7))
to compare just columns 5-7 of rows 1 and 2, but i keep getting back:
??? Index exceeds matrix dimensions.
Error in ==> etime at 41
t = 86400*(datenummx(t1(:,1:3)) - datenummx(t0(:,1:3))) + ...
You were almost there! You needed to change the 5s to 2s, that's all:
etime(x(2,2:7),x(1,2:7))
Now to get them all lets make two matrices of the date vectors but one row out of synch with each other:
fisrt set up x:
x =[ 18 2011 10 26 15 42 33 27 4
18 2011 10 26 15 42 39 17 2
18 2011 10 26 15 42 45 52 2
18 2011 10 26 15 42 47 45 3
18 2011 10 26 15 42 50 12 3
19 2011 10 31 13 6 5 36 1
19 2011 10 31 13 6 20 27 4
19 2011 10 31 13 6 22 34 5
19 2011 10 31 13 6 33 43 3
19 2011 10 31 13 6 42 42 1]
now extract the times:
Tn = x(1:end-1, 2:7);
Tnplus1 = x(2:end, 2:7);
And no to get a vector of the difference in seconds between consecutive rows:
etime(Tnplus1, Tn)
Which results in:
ans =
6
6
2
3
422595
15
2
11
9
Also if you don't care about the year month day data just set them to zero i.e.
Tn(:, 1:3) = 0;
Tnplus1(:, 1:3) = 0;
etime(Tnplus1, Tn)
ans =
6
6
2
3
-9405
15
2
11
9
Here are some simple steps:
Calculate the difference between the two rows that you want to compare
Multiply with a vector that contains the number of seconds per unit
Small scale example:
% Hours Mins Secs:
difference = ([23 12 4] - [23 11 59]);
secvec = difference .* [3600 60 1];
secdiff = sum(secvec)