I have a Perl one-liner that works fine on the command line:
perl -nle 'm"\w+:x:\d+:\d+:\S+:/S+:(\S+)$" and $h{$1}++; END{ print "$_: $h{$_}" foreach sort { $h{$b} <=> $h{$a} } keys %h }' /etc/textfile
I’ve put this into a shell file called shell.sh so the next guy won’t have to copy/paste and can just run it:
#!/bin/sh
perl -nle 'm"\w+:x:\d+:\d+:\S+:/S+:(\S+)$" and $h{$1}++; END{ print "$_: $h{$_}" foreach sort { $h{$b} <=> $h{$a} } keys %h }' /etc/textfile
I try running this on the command line and get no results; it just loads a fresh prompt with no output. Anyone see what I’m doing wrong?
Here are some system specs:
Linux version 2.6.32-220.13.1.el6.x86_64
(gcc version 4.4.6 20110731 (Red Hat 4.4.6-3) (GCC)
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Here’s a bit from the text file:
rfink:x:140:140:rat fink:/var/lib/rfink:/sbin/nologin
edible:x:16252:10001:eric idle:/users/eidle/:/bin/bash
tsawyer:x:30855:10001:tom sawyer:/users/tsawyer/:/bin/bash
karthur:x:30886:10001:King Arthur:/users/karthur/:/bin/bash
karthur:x:30886:10001:king arthur:/users/karthur/:/bin/bash
jcash:x:30887:10001:john cash:/users/jcash/:/bin/bash
hpotter:x:30887:10001:harry potter:/users/hpotter/:/bin/bash
triddle:x:30956:10001:tom riddle:/users/triddle/:/bin/bash
Quick answer
Your regex had three issues.
[^:]+to match one or more non-colon characters.\s*before$to allow optional trailing whitespace on each line.Output:
Other approaches
Perl has an awk mode, which would allow
Having to remove trailing whitespace seems to cancel the syntactic benefit.
You could use a pipeline to get the best of all worlds:
The output transposes the columns, but you get the same information.
Note the use of the regex double-negative technique in the pipeline’s first command for removing all whitespace except newlines.
7 /bin/bash 1 /sbin/nologinAs a shell script
Your question asks for a shell script, so—to vibe off daxim’s answer—that is
Note that this does not handle the pathological case of a shell named
0.If you don’t necessarily want to read the system /etc/passwd, then your script becomes
Different systems use different formats, so I recommend nailing down your expectation as in the above rather than blindly printing the last field, whatever it is. This may mean coping with the occasional empty output.