Awk doesn't represent ip addresses correctly - awk

I have done bash script for sorting extreme switches ports:
#!/bin/bash
file="/bin/visiextreme.txt"
while read ip
do
a=$(snmpwalk -v 2c -c test $ip ifDescr | column -t >> /bin/alias.txt )
b=$(snmpwalk -v 2c -c test $ip ifAlias | awk '{print '$ip' " " $4 }' | column -t >> /bin/descr.txt )
done < "$file"
c=$( paste /bin/alias.txt /bin/descr.txt | awk ' /'tr_'/{print $7 " " $6 " " $8}' | column -t >> /bin/aliasdescr.txt )
visiextreme.txt is filled with ip addresses:
10.1.96.21
10.1.96.22
192.168.0.24
....
Why after command | awk '{print '$ip' " " $4 }' | I get output:
10.10.960.21
10.10.960.22
192.16800.24
Any suggestions?

The preferred way to pass arguments from bash to awk is to supply them on the command line using the -v option. Like:
awk -vip="$ip" '{print ip" "$4 }'
This would solve your problem. However, you could still use your approach,
but then we must put double quotes around the argument to print.
Notice that the following (taken from your question):
awk '{print '$ip' " " $4 }'
expands to
awk '{print 10.1.96.21 " " $4}'
This is obviously not what we intended. So we need to put double quotes around 10.1.96.21 to make print understand that we want to print the string 10.1.96.21 and not the number 10.1. So this is a solution:
awk '{print "'$ip' " $4 }'
If you do not have double quotes around 10.1.96.21 the dots seems to expand to zeros (!) inside awk. For example:
awk 'BEGIN {print 1.2.3.4}'
gives
1.20.30.4
(Anybody who can explain this behavior?)

Related

How to move grep inside awk script?

In the below have I 3 grep commands that I would like to replace with awk's grep. so I have tried
! /000000000000/;
! /000000000000/ $0;
! /000000000000/ $3;
where I don't get an error, but testing with both the script below and
$ echo 000000000000 | awk '{ ! /000000000000/; print }'
000000000000
it doesn't skip the lines as expected.
Question
Can anyone explain why my "not grep" doesn't work in awk?
grep -v '^#' $hosts | grep -E '[0-9A-F]{12}\b' | grep -v 000000000000 | awk '{
print "host "$5" {"
print " option host-name \""$5"\";"
gsub(/..\B/,"&:", $3)
print " hardware ethernet "$3";"
print " fixed-address "$1";"
print "}"
print ""
}' > /etc/dhcp/reservations.conf
Could you please try changing your code to:
echo 000000000000 | awk '!/000000000000/'
Problem in your attempt: $ echo 000000000000 | awk '{ ! /000000000000/; print }' Since you are checking condition ! /000000000000/ which is having ; after it so that condition works well and DO NOT print anything. But then you have print after it which is NOT COMING under that condition so it simply prints that line.
awk works on pattern{action} if you are putting semi colon in between it means that condition ends before it and statement after ; is all together a new statements for awk.
EDIT: Adding possible solution by seeing OP's attempt here, not tested at all since no samples are shown by OP. Also I am using --re-interval since my awk version is old you could remove in case you have new version of awk in your box.
awk --re-interval '!/^#/ && !/000000000000/ && /[0-9A-Fa-f]{12}/{
print "host "$5" {"
print " option host-name \""$5"\";"
gsub(/..\B/,"&:", $3)
print " hardware ethernet "$3";"
print " fixed-address "$1";"
print "}"
print ""
}' "$host" > /etc/dhcp/reservations.conf
Taking a look at your code:
$ echo 000000000000 | awk '
{
! /000000000000/ # on given input this evaluates to false
# but since its in action, affects nothing
print # this prints the record regardless of whatever happened above
}'
Adding a print may help you understand:
$ echo 000000000000 | awk '{ print ! /000000000000/; print }'
0
000000000000
Removing the !:
$ echo 000000000000 | awk '{ print /000000000000/; print }'
1
000000000000
This is all I can help you with since there is not enough information for more.

String concatenation doesn't work in gawk print instruction

I have the following grep and gawk line running in windows
grep ItemDischarged D:\systems\CmcComRouting.log | gawk -v OFS=, "{print $8}" | cut -d ">" -f 1 | uniq -c | gawk -v OFS=, "{print $1,$2}" > d:\03TotalItems.log
the output is as follows
59523,ItemDischargedTlg
What I want to do is add "Lower" to the end of "ItemDischargedTlg" but cannot figure out how to do it, I have tried
{print $1,$2"Lower"}
but it prints nothing.
Thanks
This might do the trick:
gawk -v OFS=, '{$2=$2"Lower";print $1,$2}'
When trying to concatenate strings and commas you should be careful. Commas and concatenation as argument of a print instruction don't go well together.
If on windows, be careful with " and '.

awk command with BEGIN does not work for me

This is the simple awk command i am trying to write
grep "Inputs - " access.log | awk 'BEGIN { FS = "Inputs -" } ; { print $2 }'
i am trying to grep the file access.log for all the lines with "Input -" and trying to awk the part after the "Input -". This is giving the following error
awk: syntax error near line 1
awk: bailing out near line 1
I am confused what is the issue with this, this should work!!!!
I have also tried the following and it does not work
grep "Inputs - " L1Access.log | awk -F='Inputs' '{print $1}'
Here is a sample input text file
This is line number 1. I dont want this line to be part of grep output
This is line number 2. I want this line to be part of grep output. This has "Input -", I want to display only the part after "Input -" from this line using awk
your problem cannot be reproduced here:
kent$ cat f
foo - xxx
foo - yyy
foo - zzz
fooba
kent$ grep 'foo - ' f| awk 'BEGIN { FS = "foo -"};{print $2}'
xxx
yyy
zzz
There must be something wrong in your awk codes. Besides, if you want to do a grep and awk to extract the part after your Inputs - you can use grep to do it in single shot:
kent$ grep -Po 'foo - \K.*' f
xxx
yyy
zzz
Since you stated you want everything after the first instance "Inputs -", and since your grep is unnecessary:
nawk -F"Inputs -" 'BEGIN {OFS="Inputs -"} {line=""}; { for(i=2;i<=NF;i++) line=line OFS $i} {print line}' test
Your own answer will only print out the second element. In the event that you have more than one "Input -" you will be missing the remaining of the line. If you don't want the second (or third.. ) "Inputs -" in the output you could use:
nawk -F"Input -" '{ for(i=2;i<=NF;i++) print $i}' test
OK folks i see what my issue is. I am using solaris and in solaris the awk does not have capability for regex, meaning it does not support more than 1 charater in the field seperator. So i used nawk
Please refer to this post
Stackoverflow post
grep "Inputs - " L1Access.log | nawk 'BEGIN { FS = "Inputs -" } { print $2 }'
this worked.
You are not clear on what to get. Here is a sample file:
cat file
test Inputs - more data
Here is nothing to get
yes Inputs - This is what we need Inputs - but what about this?
You can then use awk to get data:
awk -F"Inputs - " 'NF>1 {print $2}' file
more data
This is what we need
or like this?
awk -F"Inputs - " 'NF>1 {print $NF}' file
more data
but what about this?
By setting separator to Inputs - and test for NF>1 it will only print lines with Inputs -

removing a space from a string by awk

How can I remove a space located between name and lastname from a string by using awk?
most of the examples are about redirecting data from command line to awk but I need to manipulate a string inside an awk script.
Convert this:
"steve john"
to:
"stevejohn"
I have a string variable which I asked user to input inside an awk script. I need to remove the spaces.
gsub is your friend. The following command basically does a global substitution of a regular expression (a single space in this case), replacing it with an empty string, on the target $0 (the whole line).
pax> echo "steve john" | awk '{ gsub (" ", "", $0); print}'
stevejohn
You can use any target, including one input by a user:
pax> awk 'BEGIN {getline xyzzy ; gsub(" ","", xyzzy) ; print xyzzy}'
hello there my name is pax
hellotheremynameispax
Use sed:
$ echo "steve john" | sed 's/ //g'
stevejohn
If you must use awk, do this:
$ echo "steve john" | gawk '{print $1 $2}'
stevejohn
Edit:
Inside a bash script, you can do this:
s="steve john" # user input
t=$(echo $s | gawk '{print $1 $2}')
echo $t
echo "john smith aaa " |\
awk 'BEGIN {FS=" "; OFS=""} {for(i=1;i<=NF;++i) {out = out OFS $i}} END {print out;}'

printing variable inside awk

In this script , I want awk to print the variables $file, $f, $order and sum/NR (all in a single row)
#!/bin/bash
for file in pmb_mpi tau xhpl mpi_tile_io fftw ; do
for f in 2.54 1.60 800 ;do
if [ ${f} = 2.54 ]
then
for order in even odd ; do
# echo ${file}_${f}_${order}_v1.xls >> P-state-summary.xls
awk '{sum+=$2} END {print ${file}_${f}_${order}_v1.xls, sum/NR}' ${file}_${f}_${order}_v1.xls >> P-state-summary.xls
done
else
# echo ${file}_${f}_v1.xls >> P-state-summary.xls
awk '{sum+=$2} END {print ${file}_${f}_v1.xls , sum/NR}' ${file}_${f}_v1.xls >> P-state-summary.xls
fi
done
done
Colud anyone of you kindly help me with this ?
awk doesn't go out and get shell variables for you, you have to pass them in as awk variables:
pax> export x=XX
pax> export y=YY
pax> awk 'BEGIN{print x "_" y}'
_
pax> awk -vx=$x -v y=$y 'BEGIN{print x "_" y}'
XX_YY
There is another way of doing it by using double quotes instead of single quotes (so that bash substitutes the values before awk sees them), but then you have to start escaping $ symbols and all sorts of other things in your awk command:
pax> awk "BEGIN {print \"${x}_${y}\"}"
XX_YY
I prefer to use explicit variable creation.
By the way, there's another solution to your previous related question here which should work.
You can do this:
echo -n "${file}_${f}_${order}_v1.xls " >> P-state-summary.xls
# or printf "${file}_${f}_${order}_v1.xls " >> P-state-summary.xls
awk '{sum+=$2} END {print sum/NR}' "${file}_${f}_${order}_v1.xls" |
tee "${file}_${f}_avrg.xls" >> P-state-summary.xls
Using echo -n or printf without a "\n" will output the text without a newline so the output of the awk command will follow it on the same line. I added a space as a separator, but you could use anything.
Using tee will allow you to write your output to the individual files and the summary file using only one awk invocation per input (order) file.