sh2lang v0.1.2
Features
- Range syntax for
forloops: Added inclusive range syntaxstart..endfor iteration (e.g.,for i in 1..10 { ... }). Supports both parenthesized(1..10)and spaced1 .. 10forms. Runtime dependency: requiresseqcommand (part of coreutils). - Path Lookup: Added
which(name)builtin to resolve executables in$PATHwithout external dependencies. Returns the path or""if not found. Exit status: returns 0 when found, 1 when not found (allowsif which("cmd") { ... }). Non-aborting:which()returning 1 does not abort the script. Paths may be relative if$PATHcontains relative entries. - Glob Expansion: Added
glob(pattern)builtin (Bash-only) to safely expand filesystem glob patterns. Returns a sorted list of matched paths; empty list if no matches. Usescompgen -Ginternally (no eval). Requires Bash 4.3+. - Recursive File Finding: Added
find_files(dir=".", name="*")builtin (Bash-only) to recursively find files usingfind ... -print0. Handles “weird” filenames (spaces, newlines) safely. Returns a sorted list of paths. Requires Bash 4.3+, GNU find, and GNU sort. - Structured Pipeline Iteration: Added
| each_line <var> { ... }pipeline consumer. Executes loop in the main process (preserving variable updates) and correctly propagates upstream exit status. Replaces fragile| while readpatterns. Bash-only (uses process substitution). - Job Control: Added
spawn(cmd),wait(pid), andwait_all(pids)builtins for running concurrent tasks.spawnstarts a background job (like&) and returns a PID.waitwaits for a PID and returns its exit code.wait_allwaits for all PIDs in a list and returns the first non-zero exit code (in list order). Supportsallow_fail=truefor non-aborting waits.spawnandwaitportable to both Bash and POSIX;wait_allfully supported on Bash, POSIX supports inline list literals only. - Stdin Line Iteration: Added
stdin_lines()iterator forforloops (e.g.for line in stdin_lines() { ... }). Correctly handles whitespace, raw lines, and empty input. Fully supported on both Bash and POSIX targets. Compliant with Policy A variable semantics. - Streaming File Discovery: Added
find0(dir=".", name=?, type=?, maxdepth=?)iterator forforloops (Bash-only). Uses NUL-delimitedfindfor safe handling of filenames with spaces, newlines, and special characters. Results are deterministically sorted. Options are compile-time validated (typemust be"f"or"d",maxdepthmust be a non-negative integer literal).
Diagnostics
- Unknown function detection: Calling an undefined function in expression context now produces a compile error with hints to use
run(...)for external commands or define the function.
Fixes
- Capture Status:
capture(..., allow_fail=true)now correctly preserves the command’s exit status instatus()across all targets, ensuring it isn’t clobbered by internal cleanup operations. [#11] sh(...)expression contexts:sh(...)insidecapture(...)and other expression contexts now correctly executes viash -c. Previously, the command string was passed as a filename argument toshrather than as code to execute.
Docs
sh()Argument Forwarding: Addedargs=args()(orargs=argv()) option tosh(...)to explicitly forward parent script positional parameters to the child shell process. By default,sh(...)starts with empty arguments to prevent accidental leakage.- Clarified
sh(...)isolation: does not inherit$@/$1; documented usingargc()/arg(n)orrun(...)instead. - Structured primitives over
sh("..."): Docs now preferglob(),find0(),spawn(),stdin_lines(), and structured pipelines oversh("...")where available. Remainingsh(...)usages are justified with# sh(...) because:comments. CI enforcement test added.
Infrastructure
- Unified GitHub Pages deployment: The APT repository URL has moved from
https://siu-mak.github.io/sh2lang/tohttps://siu-mak.github.io/sh2lang/apt/. Update your APT source line and GPG key URL accordingly. Ubuntu 24.04 (noble) is now supported alongside 22.04 (jammy).
Breaking Changes
- Hardened
arg(i):arg(i)now enforces strict runtime validation for variable indices. It aborts the script with a fatal error if the index is non-numeric,< 1, or> argc(). Previously, invalid or out-of-bounds indices might have returned empty strings or behaved unpredictably depending on the target shell. This change ensures safety against injection and logic errors. - Strict Variable Semantics: Variables must now be declared with
letbefore use or assignment.letdeclarations allow shadowing only in disjoint branches (e.g.,if true { let x=1 } else { let x=2 }), preventing accidental re-declaration errors. Diagnostic improvements now provide hints forletvssetusage. - Binder Refinements: Fixed an issue where disjoint branch declarations were incorrectly flagged as redeclarations.
each_lineloop variables now correctly preserve their value if the loop does not run (0-iterations) and the variable was previously set.
Source Code & Repository
👉 https://github.com/siu-mak/sh2lang
👉 https://github.com/siu-mak/sh2lang