0

I am looking for an awk command that prints an error message if the username it is reading from /etc/passwd does not follow certain guidelines. The guidelines are: This field must start with a letter and may contain up to a total of 8 letters, digits, underscores, hy-phens, and dots. I have managed to make sure the username is 8 characters or fewer but I am having difficulty with a command that means it must only be letters, digits, underscores, hy-phens, and dots.

Current code:

{if (length($1) >= 9) print "Error: The username has too many characters on line " NR}
{if ($1 != [a-z]) print "Error"}  //Here is where I need the command.

Do I need multiple if statements? If so can you help me find an appropriate awk statement

Thanks

  • IMHO it would be more elegant to construct a single regular expression that encapsulates the requirement, and test $1 against that in a rule.But if this is homework that may not be the intent. – steeldriver Oct 10 '16 at 23:17
  • Yea unfortunately it is homework, so I am looking for only an AWK statement – Valentino Oct 10 '16 at 23:18
  • 1
    OK but what do you really mean by "AWK statement"? Programs in awk usually consist of pattern-action pairs. Have a look at this very simple example from the GNU awk documentation, and have a think about how to change it (especially the /li/ part) to test against your requirement. You may find www.regular-expressions.info helpful. – steeldriver Oct 10 '16 at 23:29
  • How to change it is what I am having difficulty with. I was thinking something like this could work: {if ($1 !~ /[[alpha]]/) if($1 !~ /[[digits]]/) if ($1 !~ "-") The print "error" }

    Or something along the lines of this

    – Valentino Oct 10 '16 at 23:41
  • I have tried this but it is still not going:{for (i = 0; i < length($1); i++) if (substr($1, i, i) != /[A-Za-z0-9]/) print "Error some shit in here is not numbers " NR} – Valentino Oct 11 '16 at 01:18
  • There shouldn't be any need to iterate character by character - remember you want a whole string that matches a certain pattern i.e. starts with a letter (^[A-Za-z]), followed by a number of letters, digits, and selected punctuation. With some implementations of awk, you can specify a number of repetitions explicitly like {m,n} but others may only support a zero-or-more repetition modifier * in which case you will need to check the length separately. – steeldriver Oct 11 '16 at 01:54
  • try this -- awk '{if ($1 ~ /^[a-zA-Z][a-zA-Z0-9_.-]{0,7}$/) {print $1} else {print "error"}}' – jai_s Oct 11 '16 at 09:22

1 Answers1

1

I think the easiest way to do it would be to make one test for every condition on the username. This way it's easy to see what's going on and easy to modify and extend. A single regular expression would soon be too unwieldy.

/^[^a-z]/      { printf("Does not start with a letter:\t%s\n", $0)   }
length > 8     { printf("Longer than 8 characters:\t%s\n", $0)       }
/[^a-z0-9_.-]/ { printf("Contains disallowed characters:\t%s\n", $0) }

The only thing to watch out for here is the dash (-) in the last test. It must be located first or last in the [...].

Feed the awk script with the usernames from /etc/passwd:

$ cut -d ':' -f 1 /etc/passwd | awk -f usernamecheck.awk
Does not start with a letter:   _portmap
Does not start with a letter:   _identd
Does not start with a letter:   _rstatd
Does not start with a letter:   _rusersd
Does not start with a letter:   _fingerd
Does not start with a letter:   _x11
Does not start with a letter:   _switchd
Does not start with a letter:   _traceroute
Longer than 8 characters:       _traceroute

(etc.)

Kusalananda
  • 333,661