norboten · cheat sheet

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