search pattern in file and print following lines containing other pattern - bash

i have written awk to print specyfic lines from space-delimited log file.
if [ ! -f $userlog ]
then
awk -F' ' '$7$8 == "Loginitialized" {print $2" "$3" "$4" "$5" process start"}''$7$8$9 == "Applictionsuccessfullyended" {print $2" "$3" "$4" "$5" process end"}' $preplog > $userlog
fi
output sample (userlog)
2015-03-02 13:14:25 (PID 19594) process start
2015-03-02 22:42:29 (PID 30473) process start
2015-03-02 22:53:20 (PID 30473) process end
2015-03-03 07:16:55 (PID 31078) process start
2015-03-03 14:53:15 (PID 16591) process start
2015-03-03 14:54:10 (PID 18292) process start
I need to use same awk on $preplog but from last line i've printed with it.
i was trying with that but i failed:
if [ -f $userlog ]
then
lastpid=`awk -F' ' 'END{print $4}' $userlog` #pid ostatniego procesu
cat $preplog | awk 'BEGIN{ found=0} /PID /$lastpid/ Log initialized/{found=1} {if (found) {awk -F" " "$7$8 == "Loginitialized" {print $2" "$3" "$4" "$5" process start"}''$7$8$9 == "Applictionsuccessfullyended" {print $2" "$3" "$4" "$5" process end"}"} ;}' >> $userlog
fi
but my awk programing is not strong in me. I literaly have no idea how to bite it.

Let's start by cleaning up you current script:
awk -F' ' '$7$8 == "Loginitialized" {print $2" "$3" "$4" "$5" process start"}''$7$8$9 == "Applictionsuccessfullyended" {print $2" "$3" "$4" "$5" process end"}' $preplog > $userlog
Change that to:
awk '
$7$8 == "Loginitialized" { state="start" }
$7$8$9 == "Applictionsuccessfullyended" { state="end" }
state { print $2, $3, $4, $5, "process", state; state="" }
' "$preplog" > "$userlog"
for improved robustness and clarity, and to remove unnecessary constructs and redundancy.
For what you want to do next though - see if reading https://stackoverflow.com/a/18409469/1745001 helps and if not edit your question to show sample input and expected output plus a clearer, more detailed explanation of what you're trying to do.
Hang on, I think I just had a revelation after re-reading your attempted code segment - MAYBE what you want is to only analyze and operate on the last line of the input file instead of every line of it. If so that'd be:
awk '
{ var1=$7$8; var2=$7$8$9 }
END {
if (var1 == "Loginitialized") { state="start" }
if (var2 == "Applictionsuccessfullyended") { state="end" }
if (state) { print $2, $3, $4, $5, "process", state; state="" }
}
' "$preplog" > "$userlog"
If that's not what you wanted you'll need to provide more information.

Related

Testing grep output

The cmd:
STATUS=`grep word a.log | tail -1 | awk '{print $1,$2,$7,$8,$9}'`
echo "$STATUS"
The output:
2020-05-18 09:27:01 1 of 122
I need to display this $STATUS and need to do the test comparison as well.
How to compare number 122 in below? How to represent 122 in $X?
The number 122 can be any number, resulted from above cmd.
if [ "$X" -gt "300" ]
then
echo "$STATUS. This in HIGH queue ($X)"
else
echo "$STATUS. This is NORMAL ($X)"
fi
You could do it with one awk script:
awk '
/word/{ status=$1" "$2" "$7" "$8" "$9; x=$9 }
END{ printf status". This %s (%s)\n", (x>300 ? "in HIGH queue" : "is NORMAL"), x }
' a.log
I would suggest using lowercase for variables to reduce possible confusion for someone other than the original author reading the script in the future. Also using $() is typically preferable to using back-ticks -- makes quoting easier to get right.
status="$(grep word a.log | tail -1 | awk '{print $1,$2,$7,$8,$9}')"
x="$(printf '%s' "$status" | awk '{ print $NF }')"
if [ "$x" -gt 300 ]
then
echo "$status. This in HIGH queue ($x)"
else
echo "$status. This is NORMAL ($x)"
fi
Note -- we could refactor the status line a bit:
status="$(awk '/word/ { x = $1 OFS $2 OFS $7 OFS $8 OFS $9 } END { print x }' a.log)"

Validate fields for each line, in log file using awk

I'm trying to check filed on log file , line by line. For each line, check if specific filed is empty or field have wrong value .
And print line with the error message
#!/bin/bash
LOG=/log/output.log
x=false
while read -r line; do
if
(echo $line | awk -F'|' '{if ($8=="") print "Application is empty"}') ||
(echo $line | awk -F'|' '{if ($9=="") print "Http request method is empty"}') ||
(echo $line | awk -F'|' '{if ($7=="") print "Operation is empty"}')
(echo $line | awk -F'|' '{if ($13 !~ /0|1|2/) print "result(0,1,2) has a wrong value"}')
then
echo $line
fi
done < "$LOG"
Actual results:
9f2b|EDR|V1|0|V1|2019-05-14|7||||2019-05-14T08:00:40.095Z|1|0|14|19|||XXXXX|||||||||897|||||||||5b8689707|||||||
Application is empty
9f2b|EDR|V1|0|V1|2019-05-14|7||||2019-05-14T08:00:40.095Z|18|0|||||XXXXX|||||||||1234|||||||||5b868007|||||||
Application is empty
42e2|EDR|V1|0|V1|2019-05-14|7||||2019-05-14T08:00:42.532Z|22|0|||||XXXXX|||||||||235|||||||||3b6959ae||||||||
Application is empty
83ac|EDR|V1|0|V1|2019-05-14|7||||2019-05-14T08:00:42.758Z|8|0|||||XXXXX|||||||||789|||||||||5945548f|||||
Expected Result:
Application is empty
Operation is empty
Http request method is empty
83ac|EDR|V1|0|V1|2019-05-14|7||||2019-05-14T08:00:42.758Z|8|0|||||XXXXX|||||||||789|||||||||5945548f|||||
awk reads every line of the file, so there's no need for your while loop with echos. Just do:
awk -F\| ' {b=1}
$8=="" { print "Application is empty"; b=0 }
$9=="" { print "Http request method is empty"; b=0 }
$7=="" { print "Operation is empty"; b=0 }
$13 !~ /0|1|2/ {print "result(0,1,2) has a wrong value"; b=0 }
b
' /log/output.log
The main problem with your approach is that the command you are evaluating with if always succeeds, so you always print the line. To make awk fail, you would have to add exit statements to each of the awk statements. (eg echo $line | awk -F'|' '$8=="" {print "Application is empty"; exit 1 }'
This will print multiple error messages if a line fails multiple conditions, which yours will not do if you add the exit statements and short circuit the || operators.
If you want to print only one error message, you could do:
awk -F\| '
$8=="" { print "Application is empty"; next }
$9=="" { print "Http request method is empty"; next }
$7=="" { print "Operation is empty"; next }
$13 !~ /0|1|2/ {print "result(0,1,2) has a wrong value"; next }
' /log/output.log
Or, if you want to print multiple error messages, but all on one line, you could do:
awk -F\| ' {s=""}
$8=="" { printf "Application is empty"; s="; " }
$9=="" { printf "%sHttp request method is empty", s; s="; " }
$7=="" { printf "%sOperation is empty", s; s="; " }
$13 !~ /0|1|2/ {printf "%sresult(0,1,2) has a wrong value", s; s="; " }
s { print ""}
!s
' /log/output.log

system command for awk

Asked this question earlier, trying to figure out where to place " in system command and one user had suggested to use escape characters as below, but still getting the syntax error. Any leads appreciated!
free -m | awk 'NR==2{
if (($3*100/$2)>=10.00){
printf system("ps aux --sort=-%mem | awk \'NR==2{print $2}\'");
}
else
{
printf "Memory Usage: %s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2 ;
}
}'
As tripleee's comment too, I believe we could use a different mechanism (may be in shell for calculations) and then could write something, calling awk inside awk is not that cool to be honest. Could you please try following once.
free -m | awk -v s1="'" 'NR==2{
if (($3*100/$2)>=10.00){
printf system("ps aux --sort=-%mem | awk " s1 "NR==2{print $2}" s1 );
}
else
{
printf("Memory Usage: %s/%sMB %.2f%%\n", $3,$2,$3*100/$2)
}
}'
EDIT: In case one don't want to use variable for storing ' then use Octal representation of it as follows.
free -m | awk 'NR==2{
if (($3*100/$2)>=10.00){
printf system("ps aux --sort=-%mem | awk \047 NR==2{print $2} \047" );
}
else
{
printf("Memory Usage: %s/%sMB %.2f%%\n", $3,$2,$3*100/$2)
}
}'
Here is a different approach using a single awk with process substitution:
awk 'NR == FNR {
if (FNR == 2)
if ($3*100/$2 > 10)
p=1
else
printf "Memory Usage: %s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2
next
}
p && FNR == 2 {
print $2
exit
}' <(free -m) <(ps aux --sort=-%mem)

improve shell script awk & sed

I want to monitor Disk IO of a server and want to set different threshold for
the warning if %busy above 60% and
error if %busy above 80%.
From sar output need to find error disk with more than 80% busy and on 2nd line need disk more than 60 but less than 80% busy if disk not crossing theresholds then it should print 'ok' for respective category
I've created a script which will do this, but is there a better way to run sar just one time and use the same output for error & warning threshold? My system is AIX 6.1.
sar -d 2 2 |sed -n '/Average/,$p'|
sed -e 's/Average//g'|
awk 'NR> 1 {
if ($2 >80) {
print $1, $2; f=1
}
}
END { if (!f) print "ok" }'
sar -d 2 2 |
sed -n '/Average/,$p'|
sed -e 's/Average//g'|
awk 'NR> 1{ if ($2 >60 && $2 <81) { print $1, $2; f=1; } }
END { if (!f) print "ok" }'
Pls find my updated script below
bash-3.00$ cat diskio.sh
#!/bin/bash
a=`sar -d 2 2 |sed -n '/Average/,$ {s/Average//g;p;}'`
e=`$a|awk 'NR> 1{ if ($2 >40) { print $1, $2; f=1; } }
END { if (!f) print "ok" }'`
w=`$a|awk 'NR> 1{ if ($2 <40 && $2 >20) { print $1, $2; f=1; } }
END { if (!f) print "ok" }'`
echo $e
echo $w
bash-3.00$ sh -v diskio.sh
#!/bin/bash
a=`sar -d 2 2 |sed -n '/Average/,$ {s/Average//g;p;}'`
e=`$a|awk 'NR> 1{ if ($2 >40) { print $1, $2; f=1; } }
END { if (!f) print "ok" }'`
diskio.sh[3]: hdisk18: not found.
w=`$a|awk 'NR> 1{ if ($2 <40 && $2 >20) { print $1, $2; f=1; } }
END { if (!f) print "ok" }'`
diskio.sh[4]: hdisk18: not found.
echo $e
ok
echo $w
ok
bash-3.00$ sar -d 2 2 |
sed -n '/Average/,$ {s/Average//g;p;}'|
awk 'NR> 1{ if ($2 >40) { print $1, $2; f=1; } }
END { if (!f) print "ok" }'
hdisk79 135
hdisk101 85
bash-3.00$
sed -n '/Average/,$p'|sed -e 's/Average//g'
could be replaced by
sed -n '/Average/,$ {s/Average//g;p;}'
but sed does not make any evaluation of value (compare) easily so the awk for all is a better solution
This can be shorten some.
sar -d 2 2 | awk '/Average/ {t=1;next} t && NR>1 && $2>80 {print $1,$2;f=1} END { if (!f) print "ok" }'
This should do what you want
sar -d 2 2 | awk '/Average/ {t=1;next} t && NR>1 {if ($2>80) h=1;if ($2>60) l=1} END {if (h) {print "80+";exit};if (l) print "60+"}'
It will print 60+ if its above 60 and 80+ above 80
Or store it to a variable
status=$(sar -d 2 2 | awk '/Average/ {t=1;next} t && NR>1 {if ($2>80) h=1;if ($2>60) l=1} END {if (h) {print "H";exit};if (l) print "L"}')
Here it set status to L for 60+ and H for 80+
This should also print the status:
sar -d 2 2 | awk '/Average/ {t=1;next} t && NR>1 {if ($2>80) h=1;if ($2>60) {print $1,$2;l=1}} END {if (!l) print "ok"}'

Of Bash loops and if statements

I need to look at a line, and perform a quick if/then->echo on it depending on the content of column 3.
The file looks like this:
name network subnetmask
net_A 192.168.0.0 24
net_b 10.10.0.0 16
Some columns also have a blank 3rd column, and I need to have an if/then for those as well.
Psuedo-code should look like this in my mind:
snet_mask=`cat $filename | grep -i net | awk '{print $3}`
if [ $snet_mask = 24 ]
then
awk '{print "something"$1,"something else"}'
fi
if [ $snet_mask = 23 ]
then
awk '{print "something"$1,"something else"}'
fi
etc
That just doesn't work it seems, since $snet_mask becomes the value of "all" of $3, so I think I need a for loop based on grep -i net, however I don't really know.
What's the right answer? :)
Try this one-liner :
awk '$1 ~ "^net" && $3==24{print "something", $3, "something else"} $1 ~ "^net" $3==23{print "something", $3, "something else"}' file.txt
Or on multi-lines (easier to read) :
awk '
$1 ~ "^net" && $3==24{print "something", $3, "something else"}
$1 ~ "^net" && $3==23{print "something", $3, "something else"}
' file.txt
We can do it simply like this too (depends of your needs) :
awk '
$1 ~ "^net" && ($3==24 || $3==23) {print "something", $3, "something else"}
' file.txt
Or even simpler & shortest with a regex :
awk '
$1 ~ "net" && $3 ~ "^2[34]$" {print "something", $3, "something else"}
' file.txt
you could accomplish what you need in an awk statement, since you're already using awk
cat $filename | grep -i net | awk '{if($3==24) print $1; else print $0;}'
In the if statement (if 3rd col is 23), I'm printing just the first column, otherwise I'm printing everything. Obviously you can expand this to work with all of your cases
Staying in bash without external tools, you could do something like this:
while read name network netmask ; do
if [[ "$name" == net* ]] ; then
case "$netmask" in
"") echo "It's empty" ;;
24) echo "It's 24" ;;
23) echo "It's 23" ;;
*) echo "None of the above" ;;
esac
fi
done < "$filename"

Resources