Read variable from AWK - linux

I'm trying to get memory info by this command:
#!/bin/bash
set -x
cat /proc/meminfo | grep "MemFree" | tail -n 1 | awk '{ print $2 $4 }' | read numA numB
echo $numA
I'm getting this
+ awk '{ print $2 $4 }'
+ read numA numB
+ tail -n 1
+ grep MemFree
+ cat /proc/meminfo
+ echo
My attempts to read these data to variable were unsuccessful. My question is how I can read this to variables? I want to read how many memory is free like: 90841312 KB
Regards

Assign the output directly to your variable:
var=$(cat /proc/meminfo | grep "MemFree" | tail -n 1 | awk '{ print $2 $4 }')
echo $var

Using BASH you can reduce your complex commands to this:
read -r _ numA _ numB < <(grep MemFree /proc/meminfo | tail -n 1)

BTW: If you print multiple vales from awk, you need a separator:
$ echo "11 22" | awk '{print $1 }'
11
$ echo "11 22" | awk '{print $2}'
22
$ echo "11 22" | awk '{print $1 $2}'
1122
^ note no space there...
You either need a comma:
$ echo "11 22" | awk '{print $1,$2}'
11 22
Or physicality:
$ echo "11 22" | awk '{print $1" "$2}'
11 22
Because without separation, the command substitution not read what you intend:
$ read -r f1 f2 <<< $(echo "11 22" | awk '{print $1 $2}')
$ echo $f1
1122
echo $f2
# f1 got two fields and nada for f2

arr=( $(awk '/MemFree/{split($0,a)} END{print a[2], a[4]}' /proc/meminfo) )
echo "${arr[0]}"
echo "${arr[1]}"

Related

Add colons to MAC address with awk?

Below you seen my real code, I suppose it can be simplified to
$ echo 123456789012 | awk '{print $1}'
123456789012
Question
How can I get awk to add colons, it outputs 12:34:56:78:90:12 instead?
grep -v '^#' $hosts | grep -E '[0-9A-F]{12}\b' | grep -v 000000000000 | awk '{
print "host "$5" {"
print " option host-name \""$5"\";"
print " hardware ethernet "$3";"
print " fixed-address "$1";"
print "}"
print ""
}' > /etc/dhcp/reservations.conf
another way
$ echo 123456789012 | fold -w2 | paste -sd:
12:34:56:78:90:12
here is a different gawk version
$ echo 123456789012 | awk -v FPAT='..' -v OFS=':' '{$1=$1}1'
12:34:56:78:90:12
One more:
echo 0123456789ab | awk '{gsub(/..\B/,"&:")}1'
another way is to make use of gawk's FIELDWIDTHS
awk -v FIELDWIDTHS='2 2 2 2 2 2' -v OFS=":" '1+($1=$1)'
Could you please try following.
echo 123456789012 | awk '{gsub(/../,"&:");sub(/:$/,"")} 1'

Increment variable when matched awk from tail

I'm monitoring from an actively written to file:
My current solution is:
ws_trans=0
sc_trans=0
tail -F /var/log/file.log | \
while read LINE
echo $LINE | grep -q -e "enterpriseID:"
if [ $? = 0 ]
then
((ws_trans++))
fi
echo $LINE | grep -q -e "sc_ID:"
if [ $? = 0 ]
then
((sc_trans++))
fi
printf "\r WSTRANS: $ws_trans \t\t SCTRANS: $sc_trans"
done
However when attempting to do this with AWK I don't get the output - the $ws_trans and $sc_trans remains 0
ws_trans=0
sc_trans=0
tail -F /var/log/file.log | \
while read LINE
echo $LINE | awk '/enterpriseID:/ {++ws_trans} END {print | ws_trans}'
echo $LINE | awk '/sc_ID:/ {++sc_trans} END {print | sc_trans}'
printf "\r WSTRANS: $ws_trans \t\t SCTRANS: $sc_trans"
done
Attempting to do this to reduce load. I understand that AWK doesn't deal with bash variables, and it can get quite confusing, but the only reference I found is a non tail application of AWK.
How can I assign the AWK Variable to the bash ws_trans and sc_trans? Is there a better solution? (There are other search terms being monitored.)
You need to pass the variables using the option -v, for example:
$ var=0
$ printf %d\\n {1..10} | awk -v awk_var=${var} '{++awk_var} {print awk_var}'
To set the variable "back" you could use declare, for example:
$ declare $(printf %d\\n {1..10} | awk -v awk_var=${var} '{++awk_var} END {print "var=" awk_var}')
$ echo $var
$ 10
Your script could be rewritten like this:
ws_trans=0
sc_trans=0
tail -F /var/log/system.log |
while read LINE
do
declare $(echo $LINE | awk -v ws=${ws_trans} '/enterpriseID:/ {++ws} END {print "ws_trans="ws}')
declare $(echo $LINE | awk -v sc=${sc_trans} '/sc_ID:/ {++sc} END {print "sc_trans="sc}')
printf "\r WSTRANS: $ws_trans \t\t SCTRANS: $sc_trans"
done

trim ';' and split by ":"

I need to read a file like
#sys_platform:top_agent_id:channel
# 2 : 999 : 999
2:10086:10086;
2:999:999;
how to read sys_platform and top_agent_id, channel line by line
I write a shell , but not correctly
#!/bin/sh
sys_platform=""
top_agent_id=
channel=""
while read p; do
echo "line=$p"
echo $p | awk -F ':' '{print $1 $2 $3}' | read sys_platform top_agent_id channel
echo "sys_platform:${sys_platform}"
echo "top_agent_id:${top_agent_id}"
done < ./channellist.txt
result as :
line=#sys_platform:top_agent_id:channel
sys_platform:
top_agent_id:
line=# 2 : 999 : 999
sys_platform:
top_agent_id:
line=2:10086:10086;
sys_platform:
top_agent_id:
line=2:999:999;
sys_platform:
top_agent_id:
awk is your friend:
while read p; do
sys_platform=`echo $p | awk -F ':' '{print $1}'`
top_agent_id=`echo $p | awk -F ':' '{print $2}'`
channel=`echo $p | awk -F ':' '{print $3}' | tr -d ';'`
done < $filename
Nevertheless, you can do it directly with bash set builtin:
while read p; do
OFS=$IFS
IFS=':'
set -f
splitted=( $p )
set +f
sys_platform="${splitted[0]}"
top_agent_id="${splitted[1]}"
channel="${splitted[2]}"
IFS=$OFS
done < $filename
Less readable but should be more efficient.

Getting error while running script to find disk space

I am running below script:-
#!/bin/bash
threshold="20"
i=2
result=`df -kh |grep -v “Filesystem” | awk ‘{ print $5 }’ | sed ‘s/%//g’`
for percent in $result; do
if ((percent > threshold))
then
partition=`df -kh | head -$i | tail -1| awk ‘{print $1}’`
echo “$partition at $(hostname -f) is ${percent}% full”
fi
let i=$i+1
done
But I get the following error:
awk: ‘{
awk: ^ invalid char '▒' in expression
sed: -e expression #1, char 1: unknown command: `▒'
Please help me to resolve this.
What awk does not work? (your script does work fine on my Ubuntu)
This line:
result=`df -kh |grep -v "Filesystem" | awk '{ print $5 }' | sed 's/%//g'`
could be changed to:
result=$(df -kh | awk '!/Filesystem/ {print $5+0}')
Avoid using old and outdated backtics if parentheses works like this: var=$(code...)
This:
partition=`df -kh | head -$i | tail -1| awk '{print $1}'`
could be changed to:
partition=$(df -kh | awk -v line="$i" 'NR==line {print $1}')
This
let i=$i+1
could be change to:
((i++))
This would then give some like this:
#!/bin/bash
threshold="20"
i=2
result=$(df -kh | awk '!/Filesystem/ {print $5+0}')
for percent in $result; do
if ((percent > threshold))
then
partition=$(df -kh | awk -v line="$i" 'NR==line {print $1}')
echo "$partition at $(hostname -f) is ${percent}% full"
fi
((i++))
done
You're using ‘ for a single quote not '. Try re-encoding your file with an editor.
You got the answer to your syntax error, now re-write the whole script as just:
#!/bin/bash
df -kh |
awk -v t=20 -v h="$(hostname -f)" '(NR>1)&&($5+0>t){printf "%s at %s is %s full\n",$1,h,$5}'

How to make a bash copy of an awk variable?

Here is a simplified version of my problem.
if (echo "AA BB CC" | awk '{ print $1 $2 }' | grep -q "B"); then
echo $2
fi
I would like to make $2 available in bash, so I can use it elsewhere in the script.
Can that be done?
Update
I realized that I had simplified the problem too much. The awk expression should have been awk '{ print $1 $2 }' instead of just awk '{ print $2 }' which I originally posted.
You can use set:
set -- `echo "AA BB CC" | awk '{print $2}'`
case $1 in *B*) echo $1;; esac
... or if you used the awk just to split the output, let set do that part as well:
set -- `echo "AA BB CC"`
case $2 in *B*) echo $2;; esac
Remember the output of awk, test it for the regular expression and print it:
output=$( echo "AA BB CC" | awk '{ print $2 }' )
if grep -q B <<< "$output" ; then echo "$output" ; fi
You can capture stdout into a variable by using the backtick operator, e.g.
a=`echo foo`
echo $a
For your example, it would be something like:
a=`echo "AA BB CC" | awk '{ print $2 }' | grep -q "B"`
echo $a

Resources