awk NR variable not working as expected, getting the whole line while asking for first field

echo cat:
cat Records.txt
echo ""
echo Using a digit for the second record:
record_id=$(awk 'NR==2{print $1; exit}' Records.txt)
echo $record_id
echo ""
a=2
echo a is set to $a
echo ""
echo Using a variable and single quotes:
record_id=$(awk 'NR==$a{print $1; exit}' Records.txt)
echo $record_id
echo Using a variable and double quotes:
record_id=$(awk "NR==$a{print $1; exit}" Records.txt)
echo $record_id

Output

cat:
Apples 1000 happy worms
Carrots 10 happy bunnies

Using a digit for the second record:
Carrots

a is set to 2

Using a variable and single quotes:

Using a variable and double quotes:
Carrots 10 happy bunnies

I understand that double quotes are needed to use a variable, but why is it nolonger confined to output of the first field only? I only want the word Carrots.


Solution 1:

When you use single quotes, $a is not expanded by the shell, so awk sees literal NR=$a. Since the awk variable a is uninitialized, that is equivalent to NR=$0 which compares the current record number to the value of the record.

When you use double quotes, both $a and $1 are expanded by the shell, and the expression becomes NR==2{print ; exit} because $1 is empty in your interactive shell - that's why it prints the whole record.

Here are a couple of ways to pass shell variable values to awk while avoiding the trickiness of shell expansion:

awk -v a="$a" 'NR==a{print $1; exit}'

or

export a
awk 'NR==ENVIRON["a"]{print $1; exit}'

(You could use double quotes to allow expansion of $a and then prevent expansion of $1 by additional quoting/escaping ex. awk "NR==$a{print \$1; exit}" Records.txt but I recommend against it.)