Home > Software design >  Search equality in a certain field with AWK [duplicate]
Search equality in a certain field with AWK [duplicate]

Time:09-16

I am trying to get the name out of /etc/passwd using awk to search only in the 5th field of every row, and then to cut some part of that line and print it out.

This is what I wrote but it doesn't seems to work:

for iter in "$@";
do cat /etc/passwd | awk -F ":" '$5==$iter' | cut -d":" -f6;
done;

concerning the delimiter syntax, everything should be fine I guess? so my problem is in the $5==$iter, I assume. How can I change that $5==$iter to - if the 5th field of that row contains my $iter var, then cut and so on..

Sorry for the ignorance, I am a beginner :) Thanks in advance.

CodePudding user response:

See How do I use shell variables in an awk script?

-v should be used to pass shell variables into awk. Also, there's no reason to use either cat or cut here:

for iter in "$@"; do
  awk -F: -v iter="$iter" '$5==iter { print $6 }' </etc/passwd
done

CodePudding user response:

As Charles Duffy commented, your code would be more efficient if it didn't need to read /etc/passwd every pass. And while this particular loop probably doesn't need to be optimized (after all, /etc/passwd is typically not that long and most OS's would cache the file anyway after the first read), it would be interesting to see an awk script read the file only once.

That said, here's another implementation where awk is only invoked once:

printf "%s\n" "$@" | awk -F: '
  NR == FNR { etc_passwd[ $5 ] = $6;  next } 
            { print $0 , etc_passwd[ $0 ]   }
' /etc/passwd  /dev/stdin 

The NR == FNR condition is an idiom that causes its associated command only to be executed for the first file in the list of files that follows the awk script (that is, for the reading of /etc/passwd).

CodePudding user response:

You can also do everything in bash, example:

#!/bin/bash

declare -A passwd               # declare a associative array

# build the associative array "passwd" with the
# 5th field as a "key" and 6th field as "value"
while IFS=$':\n' read -a line; do      # emulate awk to extract fields
    [[ -n "${line[4]}" ]]  || continue # avoid blank "keys"
    passwd["${line[4]}"]=${line[5]}    # in bash, arrays starting in "0"
done < /etc/passwd

for iter in "$@"; do
    if [ ${passwd[$iter]   'x'} ]; then
        echo ${passwd[$iter]}
    fi
done

(This version doesn't get into accout múltiples values for 5th field)

here is a better version that can handle blank values as well, ike./script.sh '':

while IFS=$':\n' read -a line; do
    for iter in "$@"; do
        if [ "$iter" == "${line[4]}" ]; then
            echo ${line[5]}
            continue
        fi
    done
done < /etc/passwd

A pure awk solution could be:

#!/usr/bin/awk -f

BEGIN {
    FS = ":"
    for ( i = 1; i < ARGC; i   ) {
        args[ARGV[i]] = 1
        delete ARGV[i]
    }
    ARGV[1] = "/etc/passwd"
}
($5 in args) { print $6 }

and you could call as ./script.awk -f 'param1' 'param2'.

  • Related