I am looking for a one-liner awk code to find the difference between a time and system date. The time format is like this: 16:13:04,699 I want the difference in minutes. I am not quite familiar with awk, I can calculate this difference by writing a script but want to do it in one line.
Thank you.
Not exactly a one-liner:
awk -v 'time=16:13:04,699' -v "date=$(date +%H:%M:%S)" '
function abs(x) {return x<0 ? -x : x}
BEGIN {
split(time, ary, /[:,]/); t_sec = 3600*ary[1] + 60*ary[2] + ary[3]
split(date, ary, /:/); d_sec = 3600*ary[1] + 60*ary[2] + ary[3]
# output difference in minutes
print abs(t_sec - d_sec)/60
}
'
Related
I want to plot some data of a spray simulation. There is a variable called the vaporpenetrationlength, which describes the distance from the injector to the position where the mass fraction is 0.1%. The simulation created many folders for each time step. Inside those folders there is one file which contains the mass fraction and the distance.
I want to create a script which goes through all the time step folders and search inside this one file and prints out the distance where the 0.1% were measured and in which time step it was.
I found a script, but I don't understand it because I just started to learn shell scripting.
Could someone please help me step by step in building such a script? I am interested in learning it, and therefore I want to understand ever line of the code.
Thanks in advance :)
This little script outputs TimeTabLengthTabMass based on the value of the "mass fraction":
printf '%s\t%s\t%s\n' 'Time' 'Length' 'Mass'
awk '
BEGIN { FS = OFS = "\t"}
FNR == 1 {
n = split(FILENAME,path,"/")
time = sprintf("%0.7f",path[n-1])
}
NF != 2 {next}
0.001 <= $2 && $2 < 0.00101 { print time,$1,$2 }
' postProcessing/singleGraphVapPen/*/*
remark: In fact, printing the header could be done within the awk program, but doing it with a separate printf command allows you to post-process the output of awk (for ex. if you need to sort the times and/or lengths and/or masses).
notes:
FNR == 1 is true for the first line of each input file. In the corresponding block, I extract the time value from the directory name.
NF != 2 {next} is for filtering out the gnuplot commands that are at the beginning of the input files. In words, this statement means "if the number of (tab-delimited) fields in the line isn't 2, then skip"
0.001 <= $2 && $2 < 0.00101 selects the lines based on the value of their second field, which is referred to as yheptane in your script. IDK the margin of error of your "0.1% of mass fraction" so I chose convenient conditions for the sample output below.
With the sample data, the output will be:
Time Length Mass
0.0001500 0.0895768 0.00100839
0.0002000 0.102057 0.00100301
0.0002000 0.0877939 0.00100832
0.0003500 0.0827694 0.00100114
0.0009000 0.0657509 0.00100015
0.0015000 0.0501911 0.00100016
0.0016500 0.0469495 0.00100594
0.0018000 0.0436538 0.00100853
0.0021500 0.0369005 0.00100809
0.0023000 0.100328 0.00100751
As an aside, here's a script for replacing your original code:
#!/bin/bash
set -- postProcessing/singleGraphVapPen/*/*
if ! [ -f VapPen.txt ]
then
{
printf '%s\t%s\n' 'Time [s]' 'VapPen [m]'
awk '
BEGIN {FS = OFS = "\t"}
FNR == 1 {
if (NR > 1)
print time,vappen
vappen = 0
n = split(FILENAME,path,"/")
time = sprintf("%0.7f",path[n-1])
}
NF != 2 {next}
$2 >= 0.001 { vappen = $1 }
END { if (NR) print time,vappen }
' "$#" |
sort -n -k1,1
} > VapPen.txt
fi
gnuplot -e '
set title "Verdunstungspenetration";
set xlabel "Zeit [s]";
set ylabel "Verdunstungspenetrationslänge [m]";
set grid;
plot "VapPen.txt" using 1:2 with linespoints title "Vapor penetraion 0,1% mass";
pause -1 "Hit return to continue";
'
With the provided data, it reduces the execution time from several minutes to 0.15s on my computer.
I have a script in the following form:
2017-12-11 10:20:16.993 ...
2017-12-12 10:19:16.993 ...
2017-12-13 10:17:16.993 ...
and I want to extract the first column via awk - F. , and compare it to actual system time in seconds and print the line if the difference is less than 300 seconds.
> SYSTEM_TIME=$(date +%s)
> awk -F. -v system_time=$SYSTEM_TIME '{gsub(/[-:]/," ",$1); if(system_time-mktime($1) <= 300) {print $0}}' log.txt
This is my code, but I can't use mktime because it's not in the POSIX norm. Can it be done without it?
Thanks,
Ahmed
General Remark: logfiles are often incomplete. A date-time format is given, but often the time-zone is missing. When daylight-saving comes into-play it can mess up your complete karma if you are missing your timezone.
Note: In all commands below, it will be assumed that the date in the logfile is in UTC and that the system runs in UTC. If this is not the case, be aware that daylight saving time will create problems when running any of the commands below arround the time daylight-saving kicks in.
Combination of date and awk: (not POSIX)
If your date command has the -d flag (not POSIX), you can run the following:
awk -v r="(date -d '300 seconds ago' '+%F %T.%3N)" '(r < $0)'
GNU awk only:
If you want to make use of mktime, it is then easier to just do:
awk 'BEGIN{s=systime();FS=OFS="."}
{t=$1;gsub(/[-:]/," ",t); t=mktime(t)}
(t-s < 300)' logfile
I will be under the assumption that the log-files are not created in the future, so all times are always smaller than system time.
POSIX:
If you cannot make use of mktime but want to use posix only, which also implies that date does not have the -d flag, you can create your own implementation of mktime. Be aware, that the version presented here does not do any timezone corrections as is done with mktime. mktime_posix assumes that the datestring is in UTC
awk -v s="$(date +%s)" '
# Algorithm from "Astronomical Algorithms" By J.Meeus
function mktime_posix(datestring, a,t) {
split(datestring,a," ")
if (a[1] < 1970) return -1
if (a[2] <= 2) { a[1]--; a[2]+=12 }
t=int(a[1]/100); t=2-t+int(t/4)
t=int(365.25*a[1]) + int(30.6001*(a[2]+1)) + a[3] + t - 719593
return t*86400 + a[4]*3600 + a[5]*60 + a[6]
}
BEGIN{FS=OFS="."}
{t=$1;gsub(/[-:]/," ",t); t=mktime_posix(t)}
(t-s <= 300)' logfile
Related: this answer, this answer
I can think in doing this as its shorter.
#!/bin/bash
SYSTEM_TIME=$(date +%s)
LOGTIME=$( date "+%s" -d "$( awk -F'.' '{print $1}' <( head -1 inputtime.txt ))" )
DIFFERENCEINSECONDS=$( echo "$SYSTEM_TIME $LOGTIME" | awk '{ print ($1 - $2)}' )
if [[ "$DIFFERENCEINSECONDS" -gt 300 ]]
then
echo "TRIGGERED!"
fi
Hope its useful for you. Let me know.
Note : I assumed your input log could be called inputtime.txt. You need to change for your actual filename of course.
I want to know if it is possible to calculate the difference between two float number contained in a file in two distinct lines in one bash command line.
File content example :
Start at 123456.789
...
...
...
End at 123654.987
I would like to do an echo of 123654.987-123456.789
Is that possible? What is this magic command line ?
Thank you!
awk '
/Start/ { start = $3 } # 3rd field in line matching "Start"
/End/ {
end = $3; # 3rd field in line matching "End"
print end - start # Print the difference.
}
' < file
If you really want to do this on one line:
awk '/Start/ { start = $3 } /End/ { end = $3; print end - start }' < file
you can do this with this command:
start=`grep 'Start' FILENAME| cut -d ' ' -f 3`; end=`grep 'End' FILENAME | cut -d ' ' -f 3`; echo "$end-$start" | bc
You need the 'bc' program for this (for floating point math). You can install it with apt-get install bc, or yum, or rpm, zypper... OS specific :)
Bash doesn't support floating point operations. But you can split your numbers to parts and perform integer operations. Example:
#!/bin/bash
echo $(( ${2%.*} - ${1%.*} )).$(( ${2#*.} - ${1#*.} ))
Result:
./test.sh 123456.789 123654.987
198.198
EDIT:
Correct solution would be using not command line hack, but tool designed or performing fp operations. For example, bc:
echo 123654.987-123456.789 | bc
output:
198.198
Here's a weird way:
printf -- "-%s+%s\n" $(grep -oP '(Start|End) at \K[\d.]+' file) | bc
I have a html file with some variable arrays that I need to increment. I have been doing it by hand - but now is taking up too much of my time. I have been searching and trying to find the correct tool/syntax to do exactly what I want.
say I have:
file[0]=["blah0 blah0", "file0.jpg"]
file[1]=["blah1 blah1", "file1.jpg"]
file[2]=["blah2 blah2", "file2.jpg"]
What I would like to do is have the script add one to the variable number giving me room to add more variables earlier. I could specify 5 and have the result be
file[5]=["blah0 blah0", "file0.jpg"]
file[6]=["blah1 blah1", "file1.jpg"]
file[7]=["blah2 blah2", "file2.jpg"]
This is what I have tried so far - but not much luck... as it removes all the square brackets
awk -F [\]\[] '/^file\[[0-9]+\]=/ {$2="["$2+'$userinput'"]";}1' ${workdirect}/index.html > text.txt
Any advice???
#!/bin/bash
FILE=$1
awk '/^file/ {
m = match($0, "\[[0-9]+\]");
if (m) {
printf("%s%d%s\n",
substr($0, 0, RSTART),
INC + substr($0, RSTART + 1, RLENGTH - 2),
substr($0, RSTART + 2, length($0) - RSTART))
}
}' INC=$2 $1
$ foo.sh tmphtml 5
file[5]=["blah0 blah0", "file0.jpg"]
file[6]=["blah1 blah1", "file1.jpg"]
file[7]=["blah2 blah2", "file2.jpg"]
Let script be
#!/bin/bash
inc=$1
while read line; do
p1=${line%%[*}
p3=${line#*]}
p2=${line#*[}
p2=${p2%%]*}
p2=$(( ${p2} + $inc ))
echo $p1[$p2]$p3
done
Call script
$ script offset < inputfile
This is just bash, no overhead of externals.
Easier with perl:
perl -nle '$n = 5; /(file\[)([[:digit:]]+)(\]=\[.*\])/; print $1, $2 + $n, $3'
If the first line really begins file[0]= and everything is sequential, then this might work:
awk 'sub(/[0-9]+/,'$userinput'+t) {print; t=t+1}' ${workdirect}/index.html > text.txt
I have a tab delimited file and I want to perform some mathematical calculations on the columns present in file.
let the file name be sndf and $tag have some integer value, I want to first find difference between the values of column 3 and 2 then divide column 4 value with the value in $tag again divide the resultant with the difference in values of column 3 and 2 and final result is multiplied by 100.
cat $sndf | gawk '{for (i = 1; i <= NF; i += 1) {
printf "%f\t" $3 -$2 "\t", (((($4/"'$tag'")/($3-$2)))*100);
} printf "\n"}'>normal_wrt_region
the command is writing answer 4 times instead of one time to the output file..... can u all suggest an improvement?
thank you
SOLUTION: Dear all, I have solved the problem, thank you all for reading the problem and investing your time.
the command is writing answer 4 times instead of one time to the output file, can u all suggest an improvement?
Don't use the for loop if you don't need one?
cat $sndf | gawk '{ printf "%f\t" $3 -$2 "\t", (((($4/"'$tag'")/($3-$2)))*100) }'