gawk vs mawk vs BSD awk on CI Runners
The awk on a runner may be gawk (GNU), mawk (Debian/Alpine default), or BSD awk (macOS), and they differ in features and defaults.
A script that works on one runner can fail on another because awk is not one program. Knowing which features are gawk-only saves cross-platform debugging.
What it does
awk is a POSIX spec with several implementations. gawk is the feature-rich GNU version; mawk is a fast, lean version often default on Debian and Alpine (via busybox or mawk); BSD awk ships on macOS. POSIX features work everywhere; extensions do not.
Check which awk you have
awk --version 2>/dev/null | head -1 # gawk and mawk print a version
awk -W version 2>&1 | head -1 # mawk
# on macOS, plain "awk" is BSD awk; install gawk via brew
which gawk || echo "no gawk, using $(awk --version 2>&1 | head -1)"Differences that bite
| Feature | Behavior |
|---|---|
| gensub() | gawk only; mawk and BSD awk do not have it (use gsub) |
| length(array) | gawk supports it; mawk and BSD awk do not |
| \t etc. in -v | gawk processes escapes; behavior varies on others |
| Sorted for-in | gawk via PROCINFO["sorted_in"]; not in mawk/BSD |
| toupper/tolower | Available in all three |
| Dynamic regex in -F | Mostly portable, but edge cases differ across builds |
In CI
Alpine-based images often ship busybox awk or mawk, which lack gawk extensions like gensub and length(array); stick to POSIX features (gsub, split, sub) for portability, or install gawk explicitly. On macOS runners, plain awk is BSD awk, so reach for gawk if a script depends on GNU behavior.
Common errors in CI
"awk: calling undefined function gensub" means the runner has mawk or BSD awk, not gawk; rewrite with gsub or install gawk. "awk: run time error: ..." styles differ across implementations, so do not parse awk error text. mawk handles some regex and printf edge cases differently from gawk, so test the exact program on the target runner rather than assuming parity.