extract header if pattern in a column matches - linux

I am trying to extract and print header of a file if the pattern in that particular column matches.
Here is a example :
[user ~]$ cal |sed 's/July 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 31
Expected output :
if input date =31 then print the day on 31st.
Just to be clear, I cannot use date -d flag as its not supported by my OS.Probably would need awk here to crack the question.
[user ~]$ date -d 20140731 +%A
Thursday
I hope I am able to convey my question and concern clearly.

Using awk:
cal | awk -v date=31 'NR == 2 { split($0, header) } NR > 2 { for (i = 1; i <= NF; ++i) if ($i == date) { print header[NR == 3 ? i + 7 - NF : i]; exit } }'
Output:
Th

Here is a gnu awk solution:
cal | awk -v date=31 -v FIELDWIDTHS="3 3 3 3 3 3 3 3" 'NR==2 {split($0,a)} {for (i=1;i<=NF;i++) if ($i==date) print a[i]}'
Th
You set the date that you like to be displayed as a variable, so it can be change to what you like.
Or it could be written like this:
cal | awk 'NR==2 {split($0,a)} {for (i=1;i<=NF;i++) if ($i==date) print a[i]}' FIELDWIDTHS="3 3 3 3 3 3 3 3" date=31
PS FIELDWIDTH was introduced in gnu awk 2.31

Parsing the output of cal isn't really that advisable...
Can your OS's date handle -j?
date -j 073100002014 "+%a"
Thu
How is your OS at perl?
perl -MDateTime -E '$dt=DateTime->new(year=>2014,month=>7,day=>31);say $dt->day_name'
Thursday
Or, if it doesn't do perl -E, you could do
perl -MDateTime -e '$dt=DateTime->new(year=>2014,month=>7,day=>31);print $dt->day_name'
Thursday
How is your OS at php?
php -r '$jd=cal_to_jd(CAL_GREGORIAN,7,31,2014);echo(jdk($jd,2));'
Thu

Related

converting 4 digit year to 2 digit in shell script

I have file as:
$cat file.txt
1981080512 14 15
2019050612 17 18
2020040912 19 95
Here the 1st column represents dates as YYYYMMDDHH
I would like to write the dates as YYMMDDHH. So the desire output is:
81080512 14 15
19050612 17 18
20040912 19 95
My script:
while read -r x;do
yy=$(echo $x | awk '{print substr($0,3,2)}')
mm=$(echo $x | awk '{print substr($0,5,2)}')
dd=$(echo $x | awk '{print substr($0,7,2)}')
hh=$(echo $x | awk '{print substr($0,9,2)}')
awk '{printf "%10s%4s%4s\n",'$yy$mm$dd$hh',$2,$3}'
done < file.txt
It is printing
81080512 14 15
81080512 17 18
Any help please. Thank you.
Please don't kill me for this simple answer, but what about this:
cut -c 3- file.txt
You simply cut the first two digits by showing character 3 till the end of every line (the -c switch indicates that you need to cut characters (not bytes, ...)).
You can do it using single GNU AWK's substr as follows, let file.txt content be then
1981080512 14 15
2019050612 17 18
2020040912 19 95
then
awk '{$1=substr($1,3);print}' file.txt
output
81080512 14 15
19050612 17 18
20040912 19 95
Explanation: I used substr function to get 3rd and onward characters from 1st column and assign it back to said column, then I print such changed line.
(tested in gawk 4.2.1)

Get date with same day in month

I want to get all dates with the same day of week.
inputDate="2021/08/25"
That means I should get all the same day of week as inputDate.
outputDates="2021/08/04,2021/08/11,2021/08/18,2021/08/25"
I only got this so far..
inputDate="2021/08/25"
dd=$(date -d "$inputDate" +"%Y/%m/%d")
So what I'm planning is to do "date -7" and loop 5 times forward and backward and collect it then check if value of month is still the same with inputDate if not then drop it
Do you have any way to do this?
Using only shell, the easyest way to get all weekdays from a month is by using cal command:
cal -n1 8 2021
outputs:
August 2021
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 31
Then you can filter using sed, awk or other tools to reach your goal.
Example:
year=2021
month=8
day=25
weekday_number="$(date -d$year-$month-$day +%w)"
cn=$(($weekday_number + 1))
cal -n1 $month $year |
sed -r 's/(..)\s/\1\t/g;s/ +//g' |
awk -v cn=$cn -F'\t' 'NR<3 || $cn == "" {next} {print $cn}' |
while read wday; do
echo $year/$month/$wday
done
outputs:
2021/8/4
2021/8/11
2021/8/18
2021/8/25
Without using cal or ncal...
#!/bin/bash
inputDate="2021/08/25"
dow=$(date -d "$inputDate" +"%a")
month=$(date -d "$inputDate" +"%m")
outputDates=""
for x in $(seq 0 9)
do
validDate=$(date -d "$x $dow 5 week ago" +"%Y/%m/%d" | grep "/$month/")
if [ ! -z $validDate ]
then
if [ ! -z $outputDates ]
then
outputDates="$outputDates,$validDate"
else
outputDates="$validDate"
fi
fi
done
echo "$outputDates"
This script outputs:
2021/08/04,2021/08/11,2021/08/18,2021/08/25

Linux Grouping and Counting Files by attribute

I am trying to return a list of the months that files were created using the following code.
ls -l|awk '{A[$6":"]++}END{for (i in A){print i" "A[i]}}'
I am using the below code to validate each output.
ls -la | grep -c "Jan"
However as you can see from my output:
: 1
Jan: 19
Feb: 11
Mar: 28
Apr: 10
May: 14
Jun: 24
Jul: 4
Aug: 16
Sep: 10
Oct: 30
Nov: 4
Dec: 1
Output of ls|grep
I end up with 1 record showing no date. Also both January and December are short by 1. Can anyone assist?
You could do it this way using awk and sort
$ ls -l | awk '$6!=""{m[$6]++}END{for(i in m){printf "%s : %s%s",i,m[i],ORS }}' | sort -k1M
Jan : 7
Mar : 1
Apr : 8
Aug : 2
The problem comes with the first line of ls -l which doesn't contain a month field

AWK adding if statement to add zero to number range 0 to 9 ( NEED TO USE AWK)

Hi I need to format the date command output using awk and add zero before the days starting 1 to 9 .
today=`date | awk {'print $1 " " $2 " " $3'}`
So in the above the output is
Wed Mar 2
I need to add 0 to 2 to get to days of the month 1 through 9
Wed Mar 02
Ho can I add this command using the awk command
for i in 0{1..9}; do echo $i; done
So I need to add 0/zero to $3 when it's between 1 or 9
I tried doing it this way , but something is not working I get error
a3=`date|awk '{
if ($3 <=9)
print $1" "$2" " "0"$3;
else
print $1" "$2" " $3;
}'`
echo $a3
Can you please assist?
Regards
If I were you I'd just specify a format directly:
$ date '+%a %b %d'
Wed Mar 02
date takes a format string preceded by a + as its final argument.
if you must do in awk you can use printf for formatted printing
$ echo 1 2 10 20 | awk -v RS=" " '{printf "%s\t-> %02d\n",$1,$1}'
1 -> 01
2 -> 02
10 -> 10
20 -> 20

Filter log lines within a 10 minute interval

I have below lines in my dummy.text file. I would like to filter these data using bash script or awk.
Jul 28 15:05:47 * aaa has joined
Jul 28 15:07:47 * bbb has joined
Jul 28 15:08:41 * ccc has joined
Jul 28 15:13:32 * ddd has joined
Jul 28 15:14:40 * eee has joined
For example, let's say aaa has joined the session at time 15:05:47 and ccc joined the session at 15:08:47. I want to get the line who has joined equal/after 15:00:00 and before 15:10:00. The expected result would be:
Jul 28 15:05:47 * aaa has joined
Jul 28 15:07:47 * bbb has joined
Jul 28 15:08:41 * ccc has joined
Side note: after getting the expected output I'm looking to write cron job in which this data will be forward to mail.
One way :
awk -F'[ :]' '$3 == 15 && $4 >= 0 && $4 <= 10' file.txt
If you specify the 10-minute interval as 15:00:00 up to but not including 15:10:00, then:
awk -v start=15:00:00 -v end=15:10:00 '$3 >= start && $3 < end'
If you decide you want to omit the final :00 for the seconds from the times, then:
awk -v start=15:00 -v end=15:10 '$3 >= start ":00" && $3 < end ":00"'
Both of these will report on entries in the time interval on any day. If you want to restrict the date, then you can apply further conditions (on $1 and $2).
If you calculate the start and end values in shell variables, then:
start=$(…) # Calculate start time hh:mm
end=$(…) # Calculate end time hh:mm
awk -v start="$start" -v end="$end" '$3 >= start ":00" && $3 < end ":00"'
cat dummy.text | awk '$3>="15:05:47" && $3<="15:08:47" {print}'

Resources