Print out specific field using regular expression in Linux

It would be more direct, in my opinion, to use a tool like awk that can:

  • split fields for you
  • test exactly the fields you want for the values you want

For example:

awk -F: '$4 == 1001 || $4 == 1003' mypasswd

... tells awk to:

  • split the incoming lines into fields based on colons, with -F:
  • uses an "or" expression to test whether field 4 has the value 1001 or 1003
  • if the condition above is true, then print the line (the default action)

Awk can take a little bit to learn; one of the major things to understand about it is that it uses paired "pattern" and "action" statements. The "pattern" section(s) determine which "action" statements get executed.

You could rewrite the above awk to make it more explicit; by doing so, we can explicitly print whatever we want (such as the 5th field):

awk -F: '$4 == 1001 || $4 == 1003 { print $5 }'

... or to have an empty "pattern" section -- meaning, execute the "action" for every line, and then test inside the action pattern for the values:

awk -F: '{ if ($4 == 1001 || $4 == 1003)  print $5 }'

To force grep into action, you could do:

grep -E '^([^:]*:){3}(1001|1003):' mypasswd | cut -d: -f5

To tell it to look, from the beginning of the line, for the group "anything-that-isn't-a-colon any number of times, followed a colon" three times, followed by either 1001 or 1003, then followed by a colon; print the whole matching line, but then pass it to cut to print just the 5th field.

I might do this with sed

sed -n '/^.*:.*:.*:\(1001\|1003\):/p' mypasswd

The -n supresses the lines and the p at the end prints the ones that match.

you could also do it with grep

grep '^.*:.*:.*:1002\|1003:.*:.*:' mypasswd

As @JeffSchaller says, awk is the tool for the job and since OP wants regex we can just combine the two

awk -F: '$4 ~ /^100[13]$/' mypasswd

and that allows a little golf putt on the grep version

grep -E "^(.*:){3}100[13]:" mypasswd