Counting things, and the specification is the test — cheat sheet
bash, linux-basics
# counting
awk '{print $1}' file | sort | uniq -c # frequency table (sort FIRST — uniq is adjacent)
uniq -c | awk '{print $1, $2}' # strip uniq's 7-wide padding
uniq -d / -u # only duplicated / only unique lines
awk '!/^#/ && NF { c[$1]++ } END { for (k in c) print c[k], k }' file # one pass, no pre-sort
grep -c '' file # count lines
grep -v -e '^#' -e '^[[:space:]]*$' -- file # drop comments and blank/whitespace lines
# ordering
LC_ALL=C sort -k1,1nr -k2,2 # field 1 numeric descending, then field 2 as bytes ascending
# │ │ ││ └─ second key: field 2 only, default (byte) order
# │ │ │└─ r: reverse this key -n numeric, -h human sizes, -V versions
# │ └─┴─ from field 1 to field 1 (omit the end and the key runs to end of line)
sort -s # stable: preserve input order for equal keys
sort -t: -k3,3n /etc/passwd # a different field separator
LC_ALL=C # byte order, reproducible anywhere ← whenever output is compared
# options
while getopts ":n:v" opt; do case $opt in
n) n=$OPTARG ;; # ":n:" — leading colon: handle errors yourself
v) verbose=1 ;;
:) echo "$0: -$OPTARG needs an argument" >&2; exit 2 ;;
*) echo "$0: unknown option -$OPTARG" >&2; exit 2 ;;
esac; done
shift $((OPTIND - 1)) # ← forget this and $1 is still an option
[[ $n =~ ^[1-9][0-9]*$ ]] || { echo "…" >&2; exit 2; } # validate, unquoted pattern
# tests and statuses
[[ -f $f && -r $f ]] # -f regular file, -d dir, -r/-w/-x access, -s non-empty
[[ -n $s ]] / [[ -z $s ]] # non-empty / empty string
exit 0 # success (including a correct empty report)
exit 1 # could not do the job
exit 2 # misuse: bad options or arguments
# 126 not executable, 127 not found, 128+N killed by signal N (141 = SIGPIPE)
echo "msg" >&2 # errors on stderr, always
# set -e and pipelines
set -uo pipefail # -u without -e: for scripts whose pipelines end in head/grep
cmd | head -n 5 || true # head closes the pipe → upstream gets SIGPIPE → 141
# grep exits 1 when it matches nothing — that is information, not an error
# checking your own output
cmd | cat -A # line ends as $, tabs as ^I — finds stray spaces
diff <(cmd) expected # compare against a known-good file
cmd >/dev/null ; echo $? # the status alone
cmd 2>&1 >/dev/null # only stderr
bash -n script ; shellcheck script