11. What Lash Does Differently From Bash
Lash compiles to Bash, but it is not Bash syntax with a different file extension. This chapter lists the differences that matter most when reading or porting scripts.
Blocks close with end
if ready
echo "ready"
end
for file in ./*.lash
echo $"{file}"
end
Generated Bash uses fi, done, and esac; Lash source uses end.
Declarations are checked
Bash lets you assign almost anywhere. Lash distinguishes declaration from assignment.
let name = "lash"
name = "other" // error
Variables must be declared before use. let cannot be reassigned. readonly also lowers to Bash readonly behavior.
Conditions are expressions
if count > 0
echo "non-zero"
end
Lash generates Bash tests for you. Numeric comparisons use arithmetic tests. String equality uses [[ ... ]]. Regex =~ is supported in conditions only.
Booleans are numeric at runtime
true lowers to 1; false lowers to 0.
Functions return values by output
fn name()
return "lash"
end
This emits echo "lash" followed by return 0. It is designed for command-substitution style value flow, not Bash numeric return status.
argv is zero-based
let arg_count = #argv
echo $"{argv[0]}"
echo $"{arg_count}"
Bash positional parameters are one-based after $0. Lash argv[0] means the first script argument.
Maps are Bash associative arrays
let meta = {"name": "lash"}
echo $"{meta["name"]}"
The compiler lowers string-keyed maps to Bash associative arrays and enforces string keys for map literals.
Ranges are Lash syntax
for i in 1..5 step 2
echo $"{i}"
end
Ranges lower through seq and are only supported as for iterables.
wait jobs is Lash-tracked
wait jobs waits for background subshell and coproc jobs the compiler tracks. It does not scan arbitrary Bash jobs started by raw command lines.
Bare Bash is still supported
These shell forms are intentionally accepted:
set -euo pipefail
export NAME=value
source ./env.sh
shopt -s nullglob
alias ll='ls -l'
unset NAME
declare -A table
local value=1
Command substitution, process substitution, globs, redirects, heredocs, traps, background jobs, and coproc are also supported. Lash adds structure around them; it does not remove Bash from the language.