Awk Bash If-Else Issue - bash

I have a problem of being unable to printout a error message if 0 records are found.
this is what I have as of now.
function search_title
{
awk -F':' -v search="$Title" '$2 ~ search { i++;} END { printf "%d records found\n", i }' test.txt
awk -F':' -v search="$Title" '$2 ~ search { i++; printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5 } END {}' test.txt
}
function search_author
{
awk -F':' -v search="$Author" '$2 ~ search { i++;} END { printf "%d records found\n", i }' test.txt
awk -F':' -v search="$Author" '$2 ~ search { i++; printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5 } END {}' test.txt
}
function search_both
{
awk -F':' -v search="$Title" -v search1="$Author" '$1 ~ search && $2 ~ search1 { i++;} END { printf "%d records found\n", i }' test.txt
awk -F':' -v search="$Title" -v search1="$Author" '$1 ~ search && $2 ~ search1 { i++; printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5 } END {}' test.txt
}
read -p $'Title: ' Title
read -p $'Author: ' Author
if [ "$Title" == "" ];
then
search_author
elif [ "$Author" == "" ];
then
search_title
else
search_both
fi
I need a if else statement to check if the counter is 0 in awk print out "Error! Book does not exist"
For example,
Title input as DAFT
Author input as Linken
(Both value not in test.txt)
"Error! Book does not exist"
instead of the printf now which is "0 Record Found"

You don't need 2 awk command in each function:
You can combine both awk in one command:
awk -F':' -v search="$Title" -v search1="$Author" '$1 ~ search && $2 ~ search1 {
i++;
printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5;
}
END {
if (!i)
print "Error! Book does not exists!";
else
printf "%d records found\n", i;
}' test.txt

Related

How to print the remaining columns using awk?

Right now I have a command that prints my log file with a delimited | per column.
cat ambari-alerts.log | awk -F '[ ]' '{print $1 "|" $2 "|" $3 "|" $4 "|" $5 "|"}' |
grep "$(date +"%Y-%m-%d")"
Sample of the log file data is this:
2016-02-11 09:40:33,875 [OK] [MAPREDUCE2] [mapreduce_history_server_rpc_latency] (History Server RPC Latency) Average Queue Time:[0.0], Average Processing Time:[0.0]
The result of my command is this:
2016-02-11|09:40:33,875|[OK]|[MAPREDUCE2]|[mapreduce_history_server_rpc_latency]
I want to print the remaining columns. How can I do that? I tried this syntax adding $0, but unfortunately it just prints the whole line again.
awk -F '[ ]' '{print $1 "|" $2 "|" $3 "|" $4 "|" $5 "|" $0}'
Hope you can help me, newbie here in using awk.
This seems to be all you need:
$ awk '{for (i=1;i<=5;i++) sub(/ /,"|")} 1' file
2016-02-11|09:40:33,875|[OK]|[MAPREDUCE2]|[mapreduce_history_server_rpc_latency]|(History Server RPC Latency) Average Queue Time:[0.0], Average Processing Time:[0.0]
This is a bit of a hassle with awk
awk -F '[ ]' '{
printf "%s|%s|%s|%s|%s|", $1, $2, $3, $4, $5
for (i=6; i<=NF; i++) printf "%s ", $i
print ""
}'
or, replace the first 5 spaces:
awk -F '[ ]' '{
sub(/ /, "|");sub(/ /, "|");sub(/ /, "|");sub(/ /, "|");sub(/ /, "|")
print
}'
This is actually easier in bash
while IFS=" " read -r a b c d e rest; do
echo "$a|$b|$c|$d|$e|$rest"
done < file.log
Folding in your grep:
awk -F '[ ]' -v date="$(date +%Y-%m-%d)" '{
$0 ~ date {
printf "%s|%s|%s|%s|%s|", $1, $2, $3, $4, $5
for (i=6; i<=NF; i++) printf "%s ", $i
print ""
}
}'
Here is some awk that provides a somewhat more generalized approach than brute-forcing the first 5 columns:
awk '{
for (i = 1; i < 6; i++)
printf "%s|", $i
for (i = 6; i < NF; i++)
printf " %s ", $i
}' ambari-alerts.log | grep "$(date +"%Y-%m-%d")"

bash awk search function

I have been trying for hours on a certain parts of my program, I will be greatful if someone can help me. I still cannot solve the problem of adding a new line called "Book is not found" at the bottom when 0 record is found, how do i do that? How do i make the search to be case insensitive also?
awk -F':' -v search="$title" '{ if($1 == search) {printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5; i++ } else {printf "Book not found"} }END {printf "%d records found\n", i}' BookDB.txt
This give me things like
Title:dwaf
Author:
Book not found
Book not found
Book not found
Total, 0 record found
instead of
Title:wdawd
Author:
Book not found
Total, 0 record found
If a record exist, it will show
Book not found
Book not found
Book not found
Book not found
Happy Day book
Happy Day book
Happy Day book
Book not found
3 records found
instead of
Happy Day book
Happy Day book
Happy Day book
3 records found
This does not show the "book not found" message
if [ "$title" != "" ] && [ "$author" = "" ] ; then
awk -F':' -v search="$title" '{ if($1 == search) {printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5; i++ } else {printf "Book not found"} }END {printf "%d records found\n", i}' BookDB.txt
if [ "$i" < 1 ]; then
echo -n "Book not found"
fi
Next i have a error of case insensitive
i try to change the code
awk -F':' -v search="$title" 'IGNORECASE = 1;/^search/;'
BEGIN { i=0; }
{
if($1 == search) {
printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5
i++
}
}
END {
if(i >= 1) {
printf "%d records found\n", i
} else {
printf "Book not found\n"
}
}' BookDB.txt
i isn't a shell variable; it's only an awk variable. Thus, you can only reference it inside of awk code (and in the same instance of awk in which it was set).
Consider the following:
awk -F':' -v search="$title" '
BEGIN { i=0; }
{
if($1 == search) {
printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5
i++
}
}
END {
if(i >= 1) {
printf "%d records found\n", i
} else {
printf "Book not found\n"
}
}' BookDB.txt
Now, if you wanted to do this in bash, instead of awk, I might write it like so:
#!/bin/bash
# ^-- must be /bin/bash, not /bin/sh
title=$1 # or get it from somewhere else, but needs to be assigned
i=0
while IFS=: read -r -a fields; do
if [[ ${fields[0]} = "$title" ]]; then
IFS=,; printf '%s\n' "${fields[*]}"
i=$(( i + 1 ))
fi
done <BookDB.txt
if (( i > 0 )); then
echo "$i books found" >&2
else
echo "Book not found" >&2
fi
For case-insensitivity, I'd change the bash version like so:
title=${1,,} # store title in lower-case
# ...and lower-case the first field when comparing it.
if [[ ${fields[0],,} = "$title" ]]; then

awk in bash shell scripting

I am using awk function for pattern matching. If awk contains operator sign such as ++ or -- it will give me error for searching.
For example during searching
4) search_book
Title: C++ Programming in 21 Days
Author:
0 records found
however without the C++(actually without the ++, cause if i type C, i will still get the result)
4) search_book
Title: Programming in 21 Days
Author:
C++ Programming in 21 Days, Hacker Jane,$30.60,18,10
C++ Programming in 21 Days, J. D. Edwards,$50.03,15,10
C++ Programming in 21 Days, Paul Thompson,$45.00,18,10
3 records found
This is awk coding
awk -F':' -v search="$title" '$1 ~ search { i++; printf "%s, %s,$%s,%s,%s\n", $1, $2, $3, $4, $5 } END { printf "%d records found\n", i }' BookDB.txt
Update:
I have been trying for hours, but i still cannot solve the problem,if i want to add a new line called "Book is not found" at the bottom when 0 record is found, how do i do that?
How do i make it to be case insensitive also?
awk -F':' -v search="$title" '{ if($1 == search) {printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5; i++ } else {printf "Book not found"} }END {printf "%d records found\n", i}' BookDB.txt
This give me things like
Book not found
Book not found
c++ programming in 21 days
Book not found
This does not show the "book not found" message
if [ "$title" != "" ] && [ "$author" = "" ] ; then
awk -F':' -v search="$title" '{ if($1 == search) {printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5; i++ } else {printf "Book not found"} }END {printf "%d records found\n", i}' BookDB.txt
if [ "$i" < 1 ]; then
echo -n "Book not found"
fi
$1 ~ search treats the variable search as a regular expression. If you don't want that, you can use the index function which searches for literal strings, not regexes:
$ title='C++ Programming in 21 Days'
$ awk -F: -v search="$title" '(index($1, search) != 0) { i++; printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5 } END { printf "%d records found\n", i }' BookDB.txt
C++ Programming in 21 Days, Hacker Jane,$30.60,18,10
C++ Programming in 21 Days, J. D. Edwards,$50.03,15,10
C++ Programming in 21 Days, Paul Thompson,$45.00,18,10
3 records found
index($1, search) returns the location of the string search inside the string $1. If search is not found, then index returns 0.
I changed -F':' to -F:. This works because : is not a shell-active character. There is no harm in quoting it but the quotes are not necessary.
Updated Question
To get book not found:
$ awk -F: -v search="$title" '(index($1, search) != 0) { i++; printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5 } END { if (i) printf "%d records found\n", i ; else print "Book not found";}' BookDB.txt
If you have GNU awk (gawk), then adding case-insensitivity is easy:
awk -F: -v search="$title" 'BEGIN{IGNORECASE=1;} (index($1, search) != 0) { i++; printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5 } END { if (i) printf "%d records found\n", i ; else print "Book not found";}' BookDB.txt
If it makes it easier to understand, here is the same code spread over multiple lines:
awk -F: -v search="$title" '
BEGIN{
IGNORECASE=1;
}
(index($1, search) != 0){
i++;
printf "%s, %s,%s,%s,%s\n", $1, $2, $3, $4, $5
}
END{
if (i)
printf "%d records found\n", i ;
else
print "Book not found";
}
' BookDB.txt

In shell for awk, can I have variable instead of file path?

For awk,
Instead of file path can I have variable??
arr=$(awk -v str=start '$2 ~ "^" str "[0-9]*" { print $2; exit; }' /filepath)
Note output was in file path before and now It is in an variable "A".
Tried the following:
arr=$(awk -v str=start '$2 ~ "^" str "[0-9]*" { print $2; exit; }' ,$a)
arr=$(awk -v VAR="a" str=start '$2 ~ "^" str "[0-9]*" { print $2; exit; }' ,$a)
Doesn't work.
Previous post for more details:
Visit Using awk to find a string in a file!
Any help will appreciated.
This worked, thanks anubhava
Use:
arr=$(echo "$a" | awk -v str=start '$2 ~ "^" str "[0-9]*" { print $2; exit; }')

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"}'

Resources