notes

Log | Files | Refs

commit e66488e9bebb11b564df22beebb4506d90e613a9
parent 9ee2dab675340b6426c85e9c9b3fd92bf032c2b6
Author: ling0x <ling0x@users.noreply.github.com>
Date:   Fri, 12 Jun 2026 15:09:16 +0100

gawk

Diffstat:
Acommands/gawk.md | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 115 insertions(+), 0 deletions(-)

diff --git a/commands/gawk.md b/commands/gawk.md @@ -0,0 +1,115 @@ +# ================================================================================ GAWK — quick notes (Arch Linux) + +GNU Awk. Handy for shaping psql or other CLI output in a pipe. + +## INSTALL + +sudo pacman -S gawk postgresql + +psql is in the postgresql package. + +## PSQL: OUTPUT THAT PIPES WELL + +Use unaligned, one-field-per-line rows: + +psql -h localhost -U myuser -d mydb -t -A -F','\ +-c "SELECT id, name, active FROM users LIMIT 5" + +Flags: -t rows only (no header/footer) -A unaligned -F',' field separator (comma +or tab) + +## SIMPLE EXAMPLES + +Print one column + +``` + psql -h localhost -U myuser -d mydb -t -A -c "SELECT email FROM users" \ + | gawk '{ print $1 }' + + With comma-separated psql output: + + psql ... -t -A -F',' -c "SELECT id, email FROM users" \ + | gawk -F',' '{ print $2 }' + + +Filter rows +~~~~~~~~~~~ + + Keep rows where active (3rd field) is true: + + psql ... -t -A -F',' -c "SELECT id, name, active FROM users" \ + | gawk -F',' '$3 == "t" { print $1, $2 }' + + +Add a CSV header +``` + +psql ... -t -A -F',' -c "SELECT id, name FROM users"\ +| gawk -F',' 'BEGIN { print "id,name" } { print }' + +Sum a numeric column + +``` + psql ... -t -A -c "SELECT amount FROM orders" \ + | gawk '{ sum += $1 } END { print sum }' + + +key=value lines +~~~~~~~~~~~~~~~ + + psql ... -t -A -F',' -c "SELECT id, name FROM users WHERE id = 42" \ + | gawk -F',' '{ printf "id=%s name=%s\n", $1, $2 }' + + +COMPLEX EXAMPLE — MULTI-RECORD CLI OUTPUT +----------------------------------------- + +When input is not one row per line (nested structs, repeated fields): + + - set RS (record separator) to split on blocks, not newlines + - use gawk match() with a 3rd arg for capture groups (needs gawk, not awk) + - loop with match() to collect repeated fields (e.g. roles) + +Turn verbose get-all-profiles output into a table: + + kioko cad "$ENV" db user get-all-profiles | gawk ' + BEGIN { + RS = "UserProfile" + printf "%-3s %-22s %-20s %-8s %-5s %s\n", "ID", "USERNAME", "NAME", "BLOCKED", "LINK", "ROLES" + } + /TrimmedUser/ { + match($0, /id: ([0-9]+)/, a) + match($0, /username: "([^"]*)"/, u) + match($0, /first_name: "([^"]*)"/, f) + match($0, /last_name: "([^"]*)"/, l) + match($0, /blocked: ([a-z]+)/, b) + match($0, /email_link: ([0-9]+)/, e) + roles = "" + s = $0 + while (match(s, /role: ([A-Za-z]+)/, r)) { + roles = roles (roles ? "," : "") r[1] + s = substr(s, RSTART + RLENGTH) + } + printf "%-3s %-22s %-20s %-8s %-5s %s\n", a[1], u[1], f[1] " " l[1], b[1], e[1], roles + }' + + What each piece does: + + RS = "UserProfile" split stream on each profile block + /TrimmedUser/ only process records with that marker + match($0, /.../, arr) put capture group 1 into arr[1] + while (match(s, ...)) walk the string; collect every role: + printf "%-3s ..." fixed-width columns + + Same idea works on any verbose tool output, or psql nested text + (e.g. json_agg) when flat -F splitting is not enough. + + +TIPS +---- + + * Match gawk -F to the separator you pass to psql -F. + * Use gawk (not plain awk) for match(str, regex, array) captures. + * Quote SQL in -c "..." so the shell does not eat $ in awk patterns. + * In psql, \copy and \o are fine interactively; gawk fits scripts and pipes. +```