teamg
teamg

Reputation: 733

Assign two variables in one pass with awk

I have a log which every minute receives the following data:

ID: Unit3443 IP: 192.168.1.1 MAC: 00:20:c0:04:e8:ab
ID: Unit2222 IP: 192.168.2.2 MAC: 00:40:c0:05:e8:bc

I grab the last line with tail -1 /File

Is it possible to assign both of those entries to variable in one swoop? Currently I have

UnitID=`tail -1 $File|awk '{print $1}'`
UnitIP=`tail -1 $File|awk '{print $2}'`

This works but it requires the file to be read twice and my concern is during the second read the output of tail -1 will no longer be the same.

Is it possible to assign both these variables in one read of the line?

Upvotes: 1

Views: 743

Answers (4)

Mark Setchell
Mark Setchell

Reputation: 207660

You could do this:

read UnitID UnitIP < <(awk 'END{print $2, $4}' file)

Test Result

echo $UnitID
Unit2222
echo $UnitIP
192.168.2.2

As @EdMorton kindly points out in the comments, not all awk variants retain the $0..$NF variables into the END section, so the following is hopefully more widely applicable:

read UnitID UnitIP < <(awk '{a=$2; b=$4} END{print a,b}' file)

Upvotes: 1

PesaThe
PesaThe

Reputation: 7509

You can use the read builtin instead of awk:

IFS=$' \t' read -r Unit{ID,IP} _ <<< "$(tail -1 "$file")"
$ declare -p Unit{ID,IP}
declare -- UnitID="Unit2222"
declare -- UnitIP="192.168.2.2"

Or if your input file really follows the updated format (I don't see how your original code could work):

IFS=$' \t' read -r _ UnitID _ UnitIP _ <<< "$(tail -1 "$file")"

Upvotes: 1

Ed Morton
Ed Morton

Reputation: 203975

arr=( $(tail -1 "$file" | awk '{print $1, $2}') )
UnitID=${arr[0]}
UnitIP=${arr[1]}

or:

id=0
ip=1
unit=( $(tail -1 "$file" | awk '{print $1, $2}') )
echo "${unit[id]}"
echo "${unit[ip]}"

or:

line=$(tail -1 "$file" | awk '{print $1, $2}')
UnitID="${line% *}"
UnitIP="${line#* }"

Upvotes: 2

KarlMW
KarlMW

Reputation: 301

Another alternative instead of using read suggested by @PesaThe would be to do the tail in one go and use the result twice in order to avoid problems when the file changes between tails.

LINE="$(tail -1 "$File")"
UnitID="$(echo "$LINE" | awk '{print $1}')"
UnitIP="$(echo "$LINE" | awk '{print $2}')"

Note: I've also changed the sample to use $() instead of backticks - works the same way, but easier to get right.

Upvotes: 1

Related Questions