bashkit

Bashkit Compatibility Scorecard#

Feature parity tracking for bash and common tools

See also:

Legend: ✅ Implemented | ⚠️ Partial | ❌ Not implemented | N/A Security exclusion

POSIX Shell Compliance#

Bashkit provides substantial compliance with IEEE Std 1003.1-2024 (POSIX.1-2024) Shell Command Language. See knowledge/operations/limitations.md for detailed compliance status.

POSIX Category Status
Reserved Words (16) Full compliance
Special Parameters (8) Full compliance
Special Built-ins (15) 14/15 implemented
Word Expansions Substantial compliance
Redirections Full compliance
Compound Commands Full compliance

Security Exclusions: exec is intentionally not implemented for sandbox security reasons. See the compliance spec for details.

Quick Status#

Group Count
Always-on builtins 142
Feature-gated builtins (jq, git, ssh/scp/sftp, python/python3, sqlite/sqlite3, ts/typescript/node/deno/bun) 14
Total 156

Builtins Reference#

Implemented#

Builtin Flags/Features Notes
echo -n, -e, -E Basic escape sequences
printf %s, %d, %u, %x, %o, %f, width/precision GNU-style integer precision; repeats format for multiple args
cat (none) Concatenate files/stdin
true - Exit 0
false - Exit 1
exit [N] Exit with code
cd [dir] Change directory
pwd - Print working directory
test -f, -d, -e, -z, -n, -eq, -ne, -lt, -gt, -le, -ge Conditionals
[ (same as test) Alias for test
export VAR=value Export variables
read VAR, -r, -a, -d, -n, -p, -s, -t Read a record; without -r backslashes escape and \<newline> continues; status 1 at end of input
set -e, +e, positional Set options and positional params
unset VAR Unset variable
shift [N] Shift positional params
local VAR=value Local variables
source file [args] Source script; loads functions/variables, PATH search, positional params
. file [args] Alias for source
/path/to/script.sh [args] Execute script by absolute/relative path (call frame; a #! naming a registered builtin such as python3 or awk -f runs that builtin, other shebangs are stripped)
$PATH search cmd [args] Search $PATH dirs for executable scripts (after builtins)
break [N] Break from loop
continue [N] Continue loop
return [N] Return from function
: - POSIX null utility (no-op)
eval command... POSIX construct and execute command
readonly VAR[=value], -p POSIX mark variable read-only
times - POSIX display process times
grep -G/-E/-F/-P, -e, -f, -i/-y, --no-ignore-case, -v, -w, -x, -c, -l, -L, -o, -q, -s, -m, -n, -b, -H/-h, --label, -T, -Z, -z, -a, -I, --binary-files, -A/-B/-C/-NUM, --group-separator, --no-group-separator, -r/-R, -d, -D, --include/--exclude/--exclude-from/--exclude-dir; long-option prefixes GNU grep 3.11 output; BRE/ERE leftmost-longest, back-references; recursive ancestor loops skipped with a warning, files scanned under shared resource budgets
rg -i/-S/-s, -n/-N, --column, -b/--byte-offset, --vimgrep, basic --json, --stats, --null, -c, --count-matches, --include-zero, -l, --files-with-matches, --files-without-match, --files, -F, -w, -x, -a/--text, --binary, -m, -M/--max-columns, --max-columns-preview, --max-depth, -A, -B, -C, separator flags, --heading/--no-heading, --sort/--sortr, --path-separator, -g/--glob, --ignore-file, .ignore/.gitignore, --no-ignore*, --require-git/--no-require-git, -u/--unrestricted, --messages/--no-messages, -t/--type, -T/--type-not, --type-add, --type-clear, --type-list, --hidden/--no-hidden, -o, -q, -e, -f, -E/--encoding (auto, none, UTF-8, UTF-16LE/BE), -r, --passthru, --trim, -H/-I, --no-config, --line-buffered, --block-buffered, --mmap/--no-mmap, -P/--pcre2, --no-pcre2, --engine, --auto-hybrid-regex, --no-auto-hybrid-regex, --help, --version Recursive ripgrep-style search
sed s///[gpiImMN w], y, d, D, p, P, n, N, q[N], Q[N], =, l[N], z, F, a, i, c, r, R, w, W, h/H/g/G/x, b/t/T/:label, {}, #/#n; addresses N, $, /re/[IM], \cREc, first~step, a,b, a,+N, a,~N, 0,/re/, !; options -n -e -f -i[SUF] -E/-r -s -z -l N -u -- and long forms Stream editing; one stream across operands unless -s/-i
awk (also gawk, mawk, nawk) '{print}', -F, -v, loops, arrays, increment, ternary Text processing
jq .field, .[n], pipes, file args, -r, -c, -n, -s, -S, -e, -j, -f/--from-file, --tab, --arg, --argjson, -V, combined flags JSON processing
sleep N, N.N Pause execution (max 60s)
head -n N, -N First N lines (default 10)
tail -n N, -N Last N lines (default 10)
basename NAME [SUFFIX] Strip directory from path
dirname NAME Strip last path component
mkdir -p Create directories
rm -rf Remove files/directories
cp -r Copy files
mv - Move/rename files
touch -c, -d/--date, -r/--reference, -t, -a/-m Create files, set modification time
chmod MODE Change permissions (octal only)
wc -l, -w, -c Count lines/words/bytes
sort -r, -n, -u Sort lines
uniq -c, -d, -u Filter duplicate lines
cut -d DELIM, -f FIELDS Extract fields
tr -d, character ranges Translate/delete chars
date +FORMAT, -u, -R, -I, -r, -d/--date (relative, weekday, compound, epoch, ISO date-times with optional seconds and zone) Display/format date with sandboxed IANA timezone support
wait [-n] [-p VAR] [-f] [ID...] (PID or %jobspec) Wait for background jobs
jobs -l, -p List running background jobs
ps -f, aux, -o, -p Virtual process list (shell + jobs)
pgrep/pkill -f, -l, -a, -c, -x, -SIGNAL Match jobs by command
disown, fg, bg [JOBSPEC] fg waits; bg is a no-op (jobs already run)
uuidgen -r Random (v4) UUID from the OS CSPRNG
openssl rand [-hex|-base64] [-out FILE] NUM Only rand; other subcommands fail with Invalid command
make -f, -C, -n, -k, -q, -s, -i, -B, -e, -j (sequential), VAR=value GNU make subset; recipes run in the sandbox shell; no built-in implicit rules, $(eval) or vpath (L-MAKE-001..003)
curl -s, -o, -X, -d/--data, --data-raw, --data-binary, --data-urlencode, -G/--get, -H, -I, -f, -L, -w, --compressed, -u, -A, -e, -v, -m HTTP client (requires http_client feature)
wget -q, -O, --spider, --header, -U, --post-data, -t Download files (requires http_client feature)
time [-p] [-f FORMAT] [-o FILE] [-a] [-v] [--] PIPELINE Reserved-word timing; elapsed/status/Bashkit counters are truthful, host CPU/RSS fields say unavailable
timeout DURATION COMMAND Run with time limit (stub)
ls -l, -a, -h, -1, -R, -t, -F, -C, -d, -b, -N, -Q, --quoting-style (not locale/clocale) List directory contents
find GNU expression grammar (( ), !, -a, -o, ,), -H/-L/-P, -name/-iname, -path/-ipath, -regex/-iregex/-regextype, -type/-xtype, -size, -empty, -mtime/-mmin/-newer/-newerXY, -perm, -user/-group/-uid/-gid, -maxdepth/-mindepth/-depth, -print/-print0/-printf, -exec/-execdir (; and +), -delete, -prune, -quit Search for files (gaps: L-FIND-001)
rmdir -p Remove empty directories
xargs -I, -n, -d Build commands from stdin
tee -a Write to files and stdout
watch INTERVAL COMMAND Execute periodically (virtual mode)
file (none) Detect file type via magic bytes
less (none) View file (behaves like cat in virtual mode)
stat -c FORMAT Display file metadata
tar -c, -x, -t, -v, -f, -z/--gzip, -j/--bzip2, -C, -O, -P/--absolute-names, -T/--files-from, --strip-components, --exclude, -- Archive operations; auto-detects gzip/bzip2 while reading
gzip -d, -k, -f Compress files
gunzip -k, -f Decompress files
bzip2 -c, -d, -z, -k, -f Compress or decompress bzip2 streams/files
bunzip2 -c, -k, -f Decompress bzip2 streams/files
bzcat Decompress bzip2 streams/files to stdout
env -i, -u, -C, -0, [VAR=val], CMD [ARGS] Print environment or run a command in a modified one
printenv [VAR] Print environment variables
history (none) Command history (limited in virtual mode)
hostname (none) Display virtual hostname
uname -a, -s, -n, -r, -v, -m, -o System info
whoami (none) Display virtual username
id -u, -g, -n User/group IDs
nl -b, -n, -s, -i, -v, -w Number lines of files
paste -d, -s Merge lines of files
column -t, -s, -o Columnate lists
comm -1, -2, -3 Compare two sorted files
diff -u, -q/--brief Compare files line by line
strings -n, -t, -a Find printable strings in binary data
od -A, -t, -N, -j Octal/hex dump
xxd -l, -s, -c, -g, -p Hex dump
hexdump -C, -n, -s Display file in hex+ASCII

time reports#

time wraps a shell pipeline, so groups, functions, redirects, nested shells, and pipeline status behave as shell syntax rather than utility arguments. -p uses the POSIX layout. -f supports elapsed seconds (%e), elapsed hours/minutes/seconds (%E), exit status (%x), literal percent (%%), and Bashkit counters (%{commands}, %{loops}, %{work_units}). GNU host-process fields such as %U, %S, %P, and %M return unavailable; Bashkit never attributes the embedding process’s CPU or memory to a wrapped command.

-v reports the same available data with labels. -o FILE atomically replaces the report file in the VFS; -a -o FILE appends. Wrapped stdout and stderr are unchanged. Hardened profiles expose elapsed time in 100 ms lower-bound buckets.

date timezone contract#

date defaults to UTC when the shell environment has no TZ; it never reads the host process timezone. A valid IANA identifier or alias in TZ (for example America/Chicago, Etc/GMT+6, or UTC) controls display and the interpretation of timezone-naive -d values. Explicit input offsets and Z identify an instant independently of TZ; the output is then rendered in the selected zone. -u always renders UTC while naive input still uses the selected sandbox zone.

IANA transition rules apply at DST boundaries. Nonexistent local wall times fail; repeated wall times choose the earlier instant deterministically. Empty, invalid, POSIX-rule, and path-style TZ values fail closed to UTC. Formats use Chrono’s validated strftime implementation, plus GNU %N, %3N, %6N, and %9N fractional-second forms.

Recently Added#

Builtin Flags / Arguments Notes
ln -s, -f Create links
chown OWNER[:GROUP] FILE Change ownership (virtual)
kill -l, -s SIG, -n NUM, -SIG, PID/%job Terminate background jobs (exit 128+signal); stop/continue signals are ignored
trap COMMAND SIGNAL..., -p, -l Signal/event handlers
type NAME... Describe command type
which NAME... Locate a command
command -v, NAME... Run or identify commands
hash (none) No-op in sandboxed env
declare/typeset -i, -r, -x, -a, -p, -n, -l, -u Variable attributes
let EXPR... Evaluate arithmetic
getopts OPTSTRING NAME Parse positional parameters
caller [FRAME] Display call stack frame
mapfile -n, -O, -s, -t, -d Read lines into array
readarray -n, -O, -s, -t, -d Alias for mapfile
shopt -s, -u, -q, -p, -o Shell options; -o acts on set -o names
seq [FIRST [INCR]] LAST Print number sequence
tac (none) Reverse file lines
rev (none) Reverse characters per line
yes [STRING] Output repeated string
expr EXPRESSION Evaluate expressions
mktemp -d, -p, -t Create temporary files
realpath PATH Resolve path
pushd/popd/dirs standard flags Directory stack
arch (none) Virtual machine name (x86_64)
sum -r, -s BSD and System V checksums, GNU output format
shasum -a 1/224/256/384/512 Perl shasum front end over the sha*sum builtins
egrep/fgrep grep flags grep -E / grep -F
link/unlink FILE1 FILE2 / FILE Single-file link (a symlink, L-FS-001) and remove
chgrp GROUP FILE... Change group (virtual, like chown)
nohup/nice COMMAND..., nice -n N Run the command; no signal or priority effect in a sandbox
flock FILE CMD, FILE -c CMD, -n FD Creates the lock file and runs the command; locks are uncontended in one session
getconf NAME, -a POSIX config values, consistent with nproc and /proc/meminfo
tty -s “not a tty” unless the embedder sets tty(0, true), like [ -t 0 ]
sync/hostid (none) No-op / fixed virtual host id
groups/logname [USER] Virtual user only
users/who (none) Empty: no login sessions
uptime -p, -s Derived from the virtual clock
free -b, -k, -m, -g, -h, -t Fixed virtual memory, consistent with /proc/meminfo

Not Implemented#

Builtin Priority Status
exec N/A Security: intentionally excluded

Shell Syntax#

Operators#

Operator Status Example Notes
| ✅ cmd1 | cmd2 Pipeline; each stage is a subshell, shopt -s lastpipe keeps the last stage in the shell
&& ✅ cmd1 && cmd2 AND list
|| ✅ cmd1 || cmd2 OR list
; ✅ cmd1; cmd2 Sequential
& ⚠️ cmd & Parsed, async pending
! ✅ ! cmd Negate exit code

Redirections#

Redirect Status Example Notes
> ✅ cmd > file Output to file
>> ✅ cmd >> file Append to file
< ✅ cmd < file Input from file
<<< ✅ cmd <<< "string" Here-string
<<EOF ✅ Heredoc Multi-line input; unquoted bodies expand $, $( ), backticks and \$/\`/\\ escapes
2> ✅ cmd 2> file Stderr redirect
2>&1 ✅ cmd 2>&1 Stderr to stdout
&> ✅ cmd &> file Both to file
N>/N>> (N≥3) ✅ { cmd >&3; } 3>file Opens fd N only; stdout untouched

Control Flow#

Feature Status Example
if/elif/else/fi ✅ if cmd; then ...; fi
for/do/done ✅ for i in a b c; do ...; done
while/do/done ✅ while cmd; do ...; done
until/do/done ✅ until cmd; do ...; done
case/esac ✅ case $x in pat) ...;; esac
{ ... } ✅ Brace group
( ... ) ✅ Subshell
function name { } ✅ Function definition
name() { } ✅ Function definition

Expansions#

Variable Expansion#

Syntax Status Example Description
$var ✅ $HOME Simple expansion
${var} ✅ ${HOME} Braced expansion
${var:-default} ✅ ${X:-fallback} Use default if unset/empty
${var:=default} ✅ ${X:=value} Assign default if unset/empty
${var:+alt} ✅ ${X:+yes} Use alt if set
${var:?error} ✅ ${X:?missing} Error if unset/empty
${#var} ✅ ${#str} Length of value
${var#pat} ✅ ${f#*.} Remove shortest prefix
${var##pat} ✅ ${f##*/} Remove longest prefix
${var%pat} ✅ ${f%.*} Remove shortest suffix
${var%%pat} ✅ ${f%%/*} Remove longest suffix
${var/pat/repl} ✅ ${s/foo/bar} Substitute first match
${var//pat/repl} ✅ ${s//o/0} Substitute all matches
${var^} ✅ ${s^} Uppercase first
${var^^} ✅ ${s^^} Uppercase all
${var,} ✅ ${s,} Lowercase first
${var,,} ✅ ${s,,} Lowercase all
${var^^pat} ✅ ${s^^[aeiou]} Case change only for characters matching pat (also ^, ,, ,,)
${var@op} ✅ ${s@Q} Transform: Q quote, E escapes, U/u/L case, A assignment, a attributes
${arr[@]op} ✅ ${a[@]/x/y}, ${a[@]^^}, ${a[@]@Q} Pattern, case and transform operators apply per element (also ${a[i]op}, $@, $*)

Prefix Environment Assignments#

Syntax Status Example Description
VAR=val cmd ✅ TOKEN=abc printenv TOKEN Temporary env for command
Multiple prefix ✅ A=1 B=2 cmd Multiple vars in one command
No persist ✅ X=1 cmd; echo $X Var not set after command
Assignment-only ✅ X=1 (no cmd) Persists in shell variables

Command Substitution#

Syntax Status Example
$(cmd) ✅ x=$(pwd)
`cmd` ✅ Backticks, including after quoted word segments; unquoted output splits and globs

Arithmetic#

Syntax Status Example
$((expr)) ✅ $((1+2))
+, -, *, /, % ✅ Basic ops
==, !=, <, >, <=, >= ✅ Comparisons
&, | ✅ Bitwise
&&, || ✅ Logical operators
? : ✅ Ternary
=, +=, etc. ✅ Assignment operators

Other Expansions#

Syntax Status Example Description
*, ? ✅ *.txt Glob patterns
[abc] ✅ [0-9] Bracket globs
{a,b,c} ✅ {1..5} Brace expansion
~ ✅ ~/file, ~+, ~- Tilde expansion: HOME, PWD, OLDPWD
<(cmd) ✅ diff <(a) <(b) Process substitution

Special Variables#

Variable Status Description
$? ✅ Last exit code
$# ✅ Number of positional params
$@ ✅ All positional params (separate)
$* ✅ All positional params (joined)
$0 ✅ Script/function name
$1-$9 ✅ Positional parameters
$! ✅ Last background job ID (POSIX)
$$ ✅ Current PID
$- ✅ Current option flags (POSIX)
$_ ❌ Last argument
$RANDOM ✅ Random number (0-32767)
$SRANDOM ✅ 32-bit random number from the OS CSPRNG (bash 5.1); assignment ignored
$SECONDS ✅ Whole seconds since the shell (the Bash instance) started; SECONDS=N restarts the count from N
$LINENO ✅ Current line number

Arrays#

Feature Status Example
Declaration ✅ arr=(a b c)
Index access ✅ ${arr[0]}
All elements @ ✅ ${arr[@]} (separate args)
All elements * ✅ ${arr[*]} (single arg when quoted)
Array length ✅ ${#arr[@]}
Element length ✅ ${#arr[0]}
Append ✅ arr+=(d e)
Slice ✅ ${arr[@]:1:2}
Indices ✅ ${!arr[@]}
Associative ✅ declare -A

Test Operators#

File Tests#

Operator Status Description
-e file ✅ Exists
-f file ✅ Is regular file
-d file ✅ Is directory
-s file ✅ Size > 0
-r file ✅ Is readable (exists in virtual fs)
-w file ✅ Is writable (exists in virtual fs)
-x file ✅ Is executable (mode & 0o111)
-L file ✅ Is symlink

String Tests#

Operator Status Description
-z str ✅ Is empty
-n str ✅ Is non-empty
str1 = str2 ✅ Equal
str1 != str2 ✅ Not equal
str1 < str2 ✅ Less than
str1 > str2 ✅ Greater than

Numeric Tests#

Operator Status Description
-eq ✅ Equal
-ne ✅ Not equal
-lt ✅ Less than
-gt ✅ Greater than
-le ✅ Less or equal
-ge ✅ Greater or equal

Resource Limits#

Default limits (configurable):

Resource Default Notes
Commands 10,000 Per execution
Loop iterations 10,000 Per loop
Total loop iterations 1,000,000 Per execution
Function depth 100 Recursion limit
Output size 1MiB each Separate stdout and stderr caps
Parser timeout 5s Prevents infinite parse
Parser operations 100,000 Fuel-based limit
Input size 10MB Max script size
AST depth 100 Nesting limit

Filesystem#

Feature Status Notes
Virtual filesystem ✅ InMemoryFs, OverlayFs, MountableFs
Real filesystem ❌ Virtual by default
Symlinks ✅ Followed in the VFS (40-link cap); .. resolves lexically
Permissions ✅ Metadata stored, not enforced
/dev/null ✅ Interpreter-level handling (cannot be bypassed)
/dev/zero ✅ 1 MiB of zeros per read
/etc, /proc ⚠️ Synthetic, read-only (os-release, passwd, cpuinfo, …); rootfs(false) disables
/bin, /usr/bin ✅ Stub per builtin; which/type report paths, running a stub runs the builtin

Network#

Feature Status Notes
HTTP client ✅ Full implementation with security mitigations
URL allowlist ✅ Default-deny whitelist security model
curl builtin ✅ Full HTTP client; ordered data variants, @file, and -G query aggregation included
wget builtin ✅ Full downloader with -q, -O, --spider, --header, -U, --post-data, -t
Response limits ✅ 10MB max response size, 30s timeout
Redirect security ✅ Redirects require explicit -L and allowlist check
Raw sockets ❌ Not planned

Network Configuration#

use bashkit::{Bash, NetworkAllowlist};

// Enable network with URL allowlist
let bash = Bash::builder()
    .network(NetworkAllowlist::new()
        .allow("https://api.example.com")
        .allow("https://cdn.example.com/assets"))
    .build();

See knowledge/security/threat-model.md for HTTP security details.


Running Tests#

# All tests
cargo test --all-features

# Spec tests only
cargo test --test spec_tests

# Compare with real bash
cargo test --test spec_tests -- bash_comparison_tests --ignored

Roadmap#

Completed#

  • sleep builtin
  • head/tail builtins
  • File operation builtins (mkdir, rm, cp, mv, touch, chmod)
  • wc builtin
  • Text processing (sort, uniq, cut, tr)
  • Text structure (nl, paste, column)
  • File comparison (diff, comm)
  • Byte inspection (strings, od, xxd, hexdump)
  • basename/dirname builtins
  • date builtin
  • Background execution (&, wait) - jobs run concurrently on the session’s task (no stop/continue)
  • Network (curl, wget) - full HTTP implementation with security mitigations
  • timeout builtin - stub, requires interpreter-level integration
  • Process substitution (<(cmd), >(cmd))
  • Here string edge cases tested
  • set -e (errexit) - exit on command failure
  • Tilde expansion (~) - expands to $HOME
  • Special variables ($$, $RANDOM, $LINENO)
  • File test operators (-r, -w, -x, -L)
  • Stderr redirections (2>, 2>&1, &>)
  • Arithmetic logical operators (&&, ||)
  • Brace expansion ({a,b,c}, {1..5})
  • String comparison operators (< >) in test
  • Array indices ${!arr[@]}
  • /dev/null support (interpreter-level, cannot be bypassed by custom fs)

Known LLM Compatibility Gaps (Resolved)#

Identified from eval analysis, all items now implemented:

High Impact (commonly generated by LLMs):

  • chmod +x symbolic mode, apply_symbolic_mode() in fileops.rs
  • sed ampersand (&) in replacement, PR #196
  • AWK printf %x/%o/%c format specifiers, hex/octal output
  • AWK match() and gensub() functions, text extraction
  • sed \n literal newline in replacement, line splitting

Medium Impact:

  • AWK power operators (^, **), math scripts
  • AWK exit statement with code, error handling
  • AWK negation !$1, filtering empty fields
  • sed grouped commands {cmd1;cmd2}, PR #227
  • sed branch/label (b/t/:label), branching support
  • AWK ORS variable, custom output formatting
  • AWK getline, multi-file processing

Low Impact:

  • sed 0~2 step addressing, even/odd line processing
  • sed Q quiet quit command
  • sed 0,/pattern/ first match addressing
  • sed GNU rewrite, issue #2427: literal $ in the replacement, BRE/ERE translation shared by s/// and address regexes, stateful range addresses, single-stream multi-file input, preserved missing final newline, s///Ng, the y = l n N P D T z F r R w W commands, # comments and #n, atomic mode-preserving -i, and full getopt-style option parsing
  • AWK $0 modification with field re-splitting
  • AWK regex field separators (-F' +', FS = "[,;]") and regex split() separators

Not Planned#

  • Interactive features (history, job control UI)
  • Process spawning (virtual environment)
  • Raw filesystem access

See Also#