sh: add POSIX-like -c support and complete shell subset gaps

Implement sh -c COMMAND [NAME [ARG...]] in /bin/sh, add shell function
declarations/invocation support, expand export semantics (NAME, NAME=value, -p),
and make until/loop-control behavior available by default. Add focused shell
tests and update sh man-page option docs.
This commit is contained in:
Raven Scott
2026-04-26 15:28:29 -04:00
parent 9471788f6b
commit 4cdd1569af
12 changed files with 490 additions and 38 deletions
+36 -3
View File
@@ -88,9 +88,9 @@ function bareOsEmitRaw(ctx, chunk) {
}
async function run(ctx, argv) {
const script = argv[1]
if (script == null) {
ctx.console.error('usage: sh SCRIPT')
const mode = argv[1]
if (mode == null) {
ctx.console.error('usage: sh -c COMMAND [NAME [ARG ...]] | sh SCRIPT')
ctx.exitCode = 2
return
}
@@ -99,6 +99,39 @@ async function run(ctx, argv) {
ctx.exitCode = 1
return
}
if (mode === '-c') {
const command = argv[2]
if (command == null) {
ctx.console.error('sh: option requires an argument -- c')
ctx.console.error('usage: sh -c COMMAND [NAME [ARG ...]] | sh SCRIPT')
ctx.exitCode = 2
return
}
const env = ctx.vfs?.env
/** @type {Record<string, string | undefined> | null} */
const saved = env && typeof env === 'object' ? {} : null
if (saved && env) {
for (const k of ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#']) {
saved[k] = env[k]
}
env['0'] = argv[3] ?? 'sh'
const args = argv.slice(4)
for (let i = 1; i <= 9; i++) env[String(i)] = args[i - 1] ?? ''
env['#'] = String(args.length)
}
try {
await ctx.execLine(command)
} finally {
if (saved && env) {
for (const [k, v] of Object.entries(saved)) {
if (v == null) delete env[k]
else env[k] = v
}
}
}
return
}
const script = mode
let buf
try {
buf = await ctx.vfs.readFile(script)
+1 -1
View File
@@ -1,7 +1,7 @@
{
"schema": 2,
"profileId": "bare-os-posix-like",
"generatedAt": "2026-04-26T19:04:18.264Z",
"generatedAt": "2026-04-26T19:19:08.534Z",
"note": "Sparse POSIX Issue 7 coverage hints for /bin utilities. Omitted command names are not yet profiled here.",
"commandIndex": [
{
+1 -1
View File
@@ -1,6 +1,6 @@
{
"schema": 1,
"atMs": 1777230258263,
"atMs": 1777231148534,
"commands": [
"agent",
"appctl",
+8 -3
View File
@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"generatedAt": "2026-04-26T19:04:18.469Z",
"generatedAt": "2026-04-26T19:19:08.715Z",
"pages": [
{
"name": "agent",
@@ -3211,8 +3211,13 @@
"synopsis": [
"sh [OPTION]... [OPERAND]..."
],
"description": "Runs a shell script file line-by-line via ctx.execLine (same language as the interactive booter shell). This is not the interactive REPL; see man bare-os-shell for session builtins, pipelines, and jobs.",
"options": [],
"description": "Runs shell commands via ctx.execLine (same language as the interactive booter shell). Supports command-string mode (`-c`) and script-file mode (`sh SCRIPT`). This is not the interactive REPL; see man bare-os-shell for session builtins, pipelines, and jobs.",
"options": [
{
"flag": "-c COMMAND [NAME [ARG ...]]",
"meaning": "Execute command string and set positional parameters for that command context."
}
],
"keywords": [
"sh",
"bare-os",