How to extract only numbers with awk - awk

Hello i have the following output:
replication complete (rid=969811 lid=969811)
or sometimes:
no change of listener transaction id for last 0 checks (rid=971489 lid=970863)
now i want to use awk to get only the numbers from rid and lid, the following works only with the first option
|awk -F'[^0-9]*' '{print $2-$3}'

$ echo "no change of listener transaction id for last 0 checks (nid=971491 lid=970876)" |
awk -F'[()]' '{gsub(/[^0-9 ]/,"",$2); print $2}'
971491 970876
$ echo "no change of listener transaction id for last 0 checks (nid=971491 lid=970876)" |
awk -F'[()= ]' '{print $(NF-3), $(NF-1)}'
971491 970876
$ echo "no change of listener transaction id for last 0 checks (nid=971491 lid=970876)" |
awk -F'[()= ]' '{for (i=1;i<=NF;i++) m[$i]=$(i+1); print m["nid"], m["lid"]}'
971491 970876
$ echo "no change of listener transaction id for last 0 checks (nid=971491 lid=970876)" |
awk '{gsub(/.*\(|[^0-9 ]+|\).*$/,"")}1'
971491 970876
etc., etc.... The right one for you really depends what else you plan to do with the text.
Hmm, I now see in your question that you MIGHT want to print the subtraction of one number from the other instead of printing the numbers as I thought. Here's one way based on the above:
$ echo "no change of listener transaction id for last 0 checks (nid=971491 lid70876)" |
awk -F'[()= ]' '{print $(NF-3) - $(NF-1)}'
615
Alternatives left as an exercise!

You can use this awk, if your goal is to work with rid and lid values.
awk -F\(rid=\|lid=\) '{print $2-$3}' yourfile
(OR)
awk 'BEGIN{FS="(rid=|lid=)"} {print $2-$3}' yourfile

awk -F'=' '{print int($2)-int($3)}'
Works because of the way awk parses strings.

Another solution, this works in GNU-awk 4 only .... Defining Fields by Content in GAWK
echo "no change of listener transaction id for last 0 checks (rid=971489 lid=970863)" |
gawk -vFPAT='[0-9]+' '{print $(NF-1), $NF}'
you get,
971489 970863
echo "replication complete (rid=969811 lid=969811)" |
gawk -vFPAT='[0-9]+' '{print $(NF-1), $NF}'
you get,
969811 969811
Note: if, you want to do subtraction
echo "replication complete (rid=969811 lid=969811)" |
gawk -vFPAT='[0-9]+' '{print $(NF-1)-$NF}'
you get,
0

Related

shell: awk to int variable

I have a speedtest-cli skript and try to awk the result. I want to get the downloadspeed as integer, so I can compair with other results in an If, then.. condition.
part of my skript:
#!/bin/sh
speedtest-cli | awk '/Download:/ {print $2} ' > /root/tmp1
read speed1 < /root/tmp1
speedtest-cli | awk '/Download:/ {print $2} ' > /root/tmp2;
read speed2 < /root/tmp2
if [ $speed1 -gt $speed2 ];then
echo "test";fi
The problem is, that my awk result (75.27) isnt saved as integer! When it comes to if, I get an error:
sh: 75.27: bad number
I also would perfer to define the variable direct from the awk result, but that doesnt work!
speedtest-cli | var=$(awk '/Download:/ {print $2} ' > /root/tmp1)
How can I "awk" the speedtest-cli result, to get an variable that can be compaired in an if...then conditin?
please help,
thx greetings Igor
if you want to compare floating point numbers you can do within awk or with bc -l
for example
speed1=$(speedtest-cli | awk '/Download:/{print $2}')
...
speed2=$(speedtest-cli | awk '/Download:/{print $2}')
if (( $(echo "$speed1 > $speed2" | bc -l) )); then ...
another alternative is if you want to compare them as integers but don't want to lose digits due to rounding, multiply them with a large value and convert to int.
speed1000=$(speedtest-cli | awk '/Download:/{print int($2*1000)}')
...
now bash can handle integer comparisons...

Awk splitting a string and comparison

I have a string like AS|REQ|XYZ|value=12 which I am splitting with:
awk -F\| 'print {$4}' | awk -F"=" '{print $2}'
This gives the value 12.
But for the string DF|REG|EXP|value=, it comes back blank.
What I need as if my string encounters value in fourth column and is blank, throw error. Can this be done in awk command ?
Thanks
#JamesBrown has the right answer to your question as asked, but given the input you posted all you need to produce the output you want is:
awk -F'=' '{print ($NF=="" ? "Error" : $NF)}' file
If that's NOT all you need then edit your question to show some more truly representative sample input and expected output.
You could be more specific about what you mean by throwing an error. If you want the program to exit with a non-zero exit code, use if and exit with value`:
$ awk 'BEGIN{exit}'
$ echo $?
0
$ awk 'BEGIN{exit 1}'
$ echo $?
1
$ awk -F\| '{split($4,a,"="); if(a[2]=="") exit 1; else print a[2]}' foo
12
$ echo $?
1
or just print an error message and continue execution:
$ awk -F\| '{split($4,a,"="); print (a[2]==""?"ERROR":a[2])}' foo
12
ERROR
Test data used above:
$ cat foo
AS|REQ|XYZ|value=12
DF|REG|EXP|value=
Something like this perhaps?
awk -F\| '{print $4}' | awk -F"=" '{if ($2 == "") print "ERROR: Empty Value"; else print $2}'
Hope this command might work for you. The below command will behave as expected. If you have any value in the value field, it will just print the value. Else if it is blank, it prints "error". The string was placed in test.txt
awk -F\| '{if($4!="value=") {gsub("value=","",$4);print $4} else print "error" }' test.txt
Something like this -
cat f
AS|REQ|XYZ|value=12
AS|REQ|XYZ|value=
awk -F'[|=]' '{if($4 == "value" && $5 == "") {print ("Error Found at Line: ",NR)} else {print $0}}' f
AS|REQ|XYZ|value=12
Error Found at Line: 2
It search for value in 4th column and blank in 5th column.

AWK: Apply filter only if field separator is present

I surprisingly found that when you do this:
echo "hello" | awk -F'|' '{print $1;}'
you get:
hello
How to return nothing given that the field separator '|' is absent in the line ?
I do this to extract dates in beginning of log lines, but some lines don't start with a date and then give me this problem. Thanks, I am quite new in awk.
You can do this
echo "hello" | awk -F'|' 'NF>1 {print $1}'
echo "hello|1" | awk -F'|' 'NF>1 {print $1}'
hello
Only when you have more than one field, return the first field
On a file
cat testing
record1|val1
record2|val2
record3
record4|val4
awk -F'|' 'NF>1 {print $1}' testing
record1
record2
record4
Alternatively, you could use
awk -F'|' '$1==$0'
If no separator is present, then field one will contain the whole line.

How to print last two columns using awk

All I want is the last two columns printed.
You can make use of variable NF which is set to the total number of fields in the input record:
awk '{print $(NF-1),"\t",$NF}' file
this assumes that you have at least 2 fields.
awk '{print $NF-1, $NF}' inputfile
Note: this works only if at least two columns exist. On records with one column you will get a spurious "-1 column1"
#jim mcnamara: try using parentheses for around NF, i. e. $(NF-1) and $(NF) instead of $NF-1 and $NF (works on Mac OS X 10.6.8 for FreeBSD awkand gawk).
echo '
1 2
2 3
one
one two three
' | gawk '{if (NF >= 2) print $(NF-1), $(NF);}'
# output:
# 1 2
# 2 3
# two three
using gawk exhibits the problem:
gawk '{ print $NF-1, $NF}' filename
1 2
2 3
-1 one
-1 three
# cat filename
1 2
2 3
one
one two three
I just put gawk on Solaris 10 M4000:
So, gawk is the cuplrit on the $NF-1 vs. $(NF-1) issue. Next question what does POSIX say?
per:
http://www.opengroup.org/onlinepubs/009695399/utilities/awk.html
There is no direction one way or the other. Not good. gawk implies subtraction, other awks imply field number or subtraction. hmm.
Please try this out to take into account all possible scenarios:
awk '{print $(NF-1)"\t"$NF}' file
or
awk 'BEGIN{OFS="\t"}' file
or
awk '{print $(NF-1), $NF} {print $(NF-1), $NF}' file
try with this
$ cat /tmp/topfs.txt
/dev/sda2 xfs 32G 10G 22G 32% /
awk print last column
$ cat /tmp/topfs.txt | awk '{print $NF}'
awk print before last column
$ cat /tmp/topfs.txt | awk '{print $(NF-1)}'
32%
awk - print last two columns
$ cat /tmp/topfs.txt | awk '{print $(NF-1), $NF}'
32% /

awk + export value to awk

the following program needs to print the words
First
Second
Third
But because i parameter from awk not get the value from “for” loop its print all words:
First second third
First second third
First second third
How to fix awk in order to print first the “first” word second the “second” word and so on
THX
Yael
program:
for i in 1 2 3
do
echo "first second third" | awk '{print $i}'
done
You can change you code like this:
for i in 1 2 3
do
echo "first second third" | awk -v i=$i '{print $i}'
done
To use the variable 'i' from the shell.
You can also just change the record separator (RS) to have the same result :
echo "first second third" | awk 'BEGIN{RS=" "} {print $1}'
But I'm not sure if that's what you're looking for.
You could do:
for a in First Second Third
do
awk 'BEGIN { print ARGV[1] }' $a
done
Or you could do:
for a in First Second Third
do
awk -v arg=$a 'BEGIN { print arg }'
done
don't do the unnecessary. the shell for loop is not needed! Just do it with awk!
$ echo "first second third" | awk '{for(i=1;i<=NF;i++)print $i}'
Or you could use:
echo "first second third" | awk -F " " -v OFS="\n" '{print $1,$2,$3}'