How to move grep inside awk script? - awk

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.

Related

Printing only part of next line after matching a pattern

I want to print next sentence after match
My file content like this:
SSID:CoreFragment
Passphrase:WiFi1234
SSID:CoreFragment_5G
Passphrase:WiFi1234
SSID:Aleph_inCar
Passphrase:1234567890
As per my search,e.g. If I found WIFI-3(SSID) than, I want to print 1234ABCD. I used this command to search SSID:
grep -oP '^SSID:\K.+' file_name
After this search I want to print Passphrase of that particular match.
I'm working on Ubuntu 18.04
ssid=$(grep -oP '^SSID:\K.+' list_wifi.txt)
for ssid in $(sudo iwlist wlp2s0 scan | grep ESSID | cut -d '"' -f2)
do
if [ $ssid == $ssid_name ]; then
echo "SSID found...";
fi
done
I want to print next line after match.
another awk
$ awk -F: -v s="$ssid" '$0=="SSID:"s{c=NR+1} c==NR{print $2; exit}' file
1234ABCD
will only print the value if it's on the next line.
awk -F: '/WIFI-3/{getline;print $2; exit}' file
1234ABCD
Robustly (wont fail due to partial matches, etc.) and idiomatically:
$ awk -F':' 'f{print $2; exit} ($1=="SSID") && ($2=="WIFI-3"){f=1}' file
1234ABCD
Please try the following:
ssid="WIFI-3"
passphrase=$(grep -A 1 "^SSID:$ssid" file_name | tail -n 1 | cut -d: -f2)
echo "$passphrase"
which yields:
1234ABCD
Since code tags have changed the look of samples so adding this now.
var=$(awk '/SSID:[a-zA-Z]+-[0-9]+/{flag=1;next} flag{sub(/.*:/,"");value=$0;flag=""} END{print value}' Input_file)
echo "$var"
Could you please try following.
awk '/Passphrase/ && match($0,/WIFI-3 Passphrase:[0-9a-zA-Z]+/){val=substr($0,RSTART,RLENGTH);sub(/.*:/,"",val);print val;val=""}' Input_file
Using Perl
$ export ssid="WIFI-3"
$ perl -0777 -lne ' /SSID:$ENV{ssid}\s*Passphrase:(\S+)/ and print $1 ' yash.txt
1234ABCD
$ export ssid="Aleph_inCar"
$ perl -0777 -lne ' /SSID:$ENV{ssid}\s*Passphrase:(\S+)/ and print $1 ' yash.txt
1234567890
$
$ cat yash.txt
SSID:CoreFragment
Passphrase:WiFi1234
SSID:CoreFragment_5G
Passphrase:WiFi1234
SSID:Aleph_inCar
Passphrase:1234567890
SSID:WIFI-1
Passphrase:1234ABCD
SSID:WIFI-2
Passphrase:123456789
SSID:WIFI-3
Passphrase:1234ABCD
You can capture it in variables as
$ passphrase=$(perl -0777 -lne ' /SSID:$ENV{ssid}\s*Passphrase:(\S+)/ and print $1 ' yash.txt)
$ echo $passphrase
1234567890
$

Run command inside awk and store result inplace

I have a script that I need to run on every value. It basically return a number by taking an argument, like below
>>./myscript 4832
>>1100
my.csv contains the following:
123,4832
456,4833
789,4834
My command
cat my.csv | awk -F',' '{$3=system("../myscript $2");print $1,$2,$3'}
myscript is unable to understand that I'm passing the second input field $2 as argument. I need the output from the script to be added to the output as my 3rd column.
The expected output is
123,4832,1100
456,4833,17
789,4834,42
where the third field is the output from myscript with the second field as the argument.
If you are attempting to add a third field with the output from myscript $2 where $2 is the value of the second field, try
awk -F , '{ printf ("%s,%s,", $1, $2); system("../myscript " $2) }' my.csv
where we exploit the convenient fact that the output from myscript will complete the output without a newline with the calculated value and a newline.
This isn't really a good use of Awk; you might as well do
while IFS=, read -r first second; do
printf "%s,%s," "$first" "$second"
../mycript "$second"
done <my.csv
I'm assuming you require comma-separated output; changing this to space-separated is obviously a trivial modification.
The syntax you want is:
awk 'BEGIN{FS=OFS=","}
{
cmd = "./myscript \047" $2 "\047"
val = ( (cmd | getline line) > 0 ? line : "NaN" )
close(cmd)
print $0, val
}
' file
Tweak the getline part to do different error handling if you like and make sure you read and fully understand http://awk.freeshell.org/AllAboutGetline before using getline.
We can use in gnu-awk Two-Way Communications with Another Process
awk -F',' '{"../myscript "$2 |& getline v; print $1,$2,v}' my.csv
you get,
123 4832 1100
456 4833 17
789 4834 42
awk -F',' 'BEGIN { OFS=FS }{"../myscript "$2 |& getline v; print $1,$2,v}' my.csv
you get,
123,4832,1100
456,4833,17
789,4834,42
from GNU awk online documentation:
system: Execute the operating system command command and then return to the awk program. Return command’s exit status (see further on).
you need to use getline getline piped documentation
You need to specify the $2 separately in the string concatenation, that is
awk -F',' '{ system("echo \"echo " $1 "$(../myexecutable " $2 ") " $3 "\" | bash"); }' my.csv

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 -

Awk doesn't represent ip addresses correctly

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?)

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.