8

I am trying to print from a file using awk, but my output is empty. Here is my code so far

accountNum=$1
while read -r LINE || [[ -n $LINE ]] ; do
            awk -F',' '{ if($1==accountNum) { print $3.$2 } }' Accounts
done < Accounts

I have also tried this:

accountNum=$1
while read -r LINE || [[ -n $LINE ]] ; do
            echo $LINE  | awk -F',' '{ if($1==accountNum) { print $3.$2 } }' 
done < Accounts

The input file is :

1,Doe,John
2,Rooney,Wayne
3,Smith,Will
4,Crow,Russel
5,Cruise,Tom

The expected output when I run the file is

$./file.sh 3
Will Smith

But I get the following

$./file.sh 3
$

That is nothing is being printed out. I know the solution with cut, but I want to use awk.

4 Answers 4

9

You should use -v option of awk:

awk -F',' -v accNum="$1" '$1 == accNum {print $3,$2}'

With $1 in double quote, the shell will handle all its special character ( if has ) for you.

3

You have:

accountNum=$1
awk -F',' '{ if($1==accountNum) { print $3.$2 } }' Accounts

How does the shell variable accountNum get into awk? It doesn't: you need to provide its value to awk explicitly. You can use:

awk -F',' '{ if($1=='"$accountNum"') { print $3.$2 } }' Accounts

which leaves single quotes and has the shell substitute the value of its variable into the awk command, then reenters single quotes for the rest of the command string.

A better or at least more idiomatic script would be:

#!/bin/sh
accountNum=$1
awk -F, '$1 == "'"$accountNum"'" { print $3,$2 }' Accounts

which deals with non-numeric account numbers (quoting the substituted variable), uses a pattern block instead of an explicit if (the {} block will run if the test before it is true), and prints a space between the names as you wanted (because of ,). If you prefer to use if explicitly, move the test inside your existing if statement.

Depending on your real goal awk may not be the best fit for what you're doing. The above still fails if the script's $1 has quotes in it. The shell loop you had wasn't doing anything useful, although it would have repeated the output many times.

2
  • are you saying I should remove the while loop? :)
    – gkmohit
    Jul 21, 2014 at 3:15
  • At least for the examples it isn't doing anything to help you. Jul 21, 2014 at 3:22
3

Your script already practically does the job without any awk at all:

while IFS=, read -r num last first
    do  [ $((num==accountNum)) -eq 1 ] && 
        printf '%s.%s\n' "$first" "$last"
done < Accounts

I'm not suggesting that this is a better or more efficient solution than using awk alone, but if you want the while...read loop, this certainly beats separate awk processes per each line. Just an FYI, I guess.

1
  • 1
    Not just one awk for every line, but that awk reads the entire file again for every line that the shell itself reads. Way to get a O(n^2) algorithm. May 21, 2020 at 8:50
1
#!/bin/bash

awk -v a="$1" -F ',' '$1 == a { print $3, $2 }' Accounts

With -v a="$1" we set the awk variable a to the value of the script's first command line argument, then we specify that the input is comma separated with -F ','. If the first column is equal to the value of a, print the two other columns in reverse order.

You get nothing in your output as you are comparing the first column to the awk variable accountNum, which is unset.

Had there been an entry whose first column had 0 (zero) in it, that entry would have been printed. This is because the value of unset variables in awk evaluates to zero.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .