Updates
This commit is contained in:
@@ -740,6 +740,17 @@ export function tokenize(line) {
|
|||||||
i++
|
i++
|
||||||
let inner = ''
|
let inner = ''
|
||||||
while (i < line.length && line[i] !== '"') {
|
while (i < line.length && line[i] !== '"') {
|
||||||
|
if (line[i] === '$' && line[i + 1] === '(' && line[i + 2] === '(') {
|
||||||
|
const close = findArithmeticClose(line, i + 3)
|
||||||
|
if (close < 0) {
|
||||||
|
inner += line.slice(i)
|
||||||
|
i = line.length
|
||||||
|
break
|
||||||
|
}
|
||||||
|
inner += line.slice(i, close + 2)
|
||||||
|
i = close + 2
|
||||||
|
continue
|
||||||
|
}
|
||||||
if (line[i] === '\\' && i + 1 < line.length) {
|
if (line[i] === '\\' && i + 1 < line.length) {
|
||||||
i++
|
i++
|
||||||
inner += line[i++]
|
inner += line[i++]
|
||||||
@@ -751,6 +762,17 @@ export function tokenize(line) {
|
|||||||
parts.push({ q: 'd', t: inner })
|
parts.push({ q: 'd', t: inner })
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if (ch === '$' && line[i + 1] === '(' && line[i + 2] === '(') {
|
||||||
|
const close = findArithmeticClose(line, i + 3)
|
||||||
|
if (close < 0) {
|
||||||
|
cur.t += line.slice(i)
|
||||||
|
i = line.length
|
||||||
|
break
|
||||||
|
}
|
||||||
|
cur.t += line.slice(i, close + 2)
|
||||||
|
i = close + 2
|
||||||
|
continue
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
/\s/.test(ch) ||
|
/\s/.test(ch) ||
|
||||||
ch === '|' ||
|
ch === '|' ||
|
||||||
|
|||||||
@@ -3012,6 +3012,15 @@ test('tokenize records quote parts for glob (literal * in quotes)', async (t) =>
|
|||||||
t.is(lit.parts[0].t, '*')
|
t.is(lit.parts[0].t, '*')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('tokenize keeps arithmetic expansion in one word token', async (t) => {
|
||||||
|
const toks = tokenize('n=$((n+1)); echo "$((n+2))"')
|
||||||
|
const words = toks.filter((x) => x.type === 'word').map((x) => x.value)
|
||||||
|
t.ok(words.includes('n=$((n+1))'))
|
||||||
|
t.ok(words.includes('$((n+2))'))
|
||||||
|
t.is(toks.filter((x) => x.type === 'op' && x.value === '(').length, 0)
|
||||||
|
t.is(toks.filter((x) => x.type === 'op' && x.value === ')').length, 0)
|
||||||
|
})
|
||||||
|
|
||||||
test('execShellLine pathname glob and noglob', async (t) => {
|
test('execShellLine pathname glob and noglob', async (t) => {
|
||||||
const dir = testCorestoreDir('shglob')
|
const dir = testCorestoreDir('shglob')
|
||||||
const store = new Corestore(dir)
|
const store = new Corestore(dir)
|
||||||
@@ -4499,6 +4508,10 @@ async function run(ctx) {
|
|||||||
lines.length = 0
|
lines.length = 0
|
||||||
await execShellLine(ctx, 'if false; then echo x; fi')
|
await execShellLine(ctx, 'if false; then echo x; fi')
|
||||||
t.ok(!lines.some((l) => l.includes('x')))
|
t.ok(!lines.some((l) => l.includes('x')))
|
||||||
|
ctx.exitCode = 0
|
||||||
|
await execShellLine(ctx, 'n=0; if true; then n=$((n+1)); fi; echo $n')
|
||||||
|
t.is(ctx.exitCode, 0)
|
||||||
|
t.ok(lines.some((l) => l.includes('1')))
|
||||||
await store.close()
|
await store.close()
|
||||||
rmSync(dir, { recursive: true, force: true })
|
rmSync(dir, { recursive: true, force: true })
|
||||||
})
|
})
|
||||||
@@ -6323,6 +6336,16 @@ test('tier-1 sh -c executes command and sets positional args', async (t) => {
|
|||||||
await runBinCommand(ctx, ['sh', '-c', 'false'])
|
await runBinCommand(ctx, ['sh', '-c', 'false'])
|
||||||
t.is(ctx.exitCode, 1)
|
t.is(ctx.exitCode, 1)
|
||||||
|
|
||||||
|
lines.length = 0
|
||||||
|
ctx.exitCode = 0
|
||||||
|
await runBinCommand(ctx, [
|
||||||
|
'sh',
|
||||||
|
'-c',
|
||||||
|
'n=0; if true; then n=$((n+1)); fi; echo $n'
|
||||||
|
])
|
||||||
|
t.is(ctx.exitCode, 0)
|
||||||
|
t.ok(lines.includes('1'))
|
||||||
|
|
||||||
await store.close()
|
await store.close()
|
||||||
rmSync(dir, { recursive: true, force: true })
|
rmSync(dir, { recursive: true, force: true })
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -95,6 +95,15 @@ test('run_command wraps compound shell with sh -c before capture redirection', a
|
|||||||
t.ok(seen[0].startsWith("sh -c 'for x in a b; do if true; then echo $x; fi; done'"))
|
t.ok(seen[0].startsWith("sh -c 'for x in a b; do if true; then echo $x; fi; done'"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('run_command wraps combined if + arithmetic expansion probe', async (t) => {
|
||||||
|
const { ctx, seen } = makeCtx()
|
||||||
|
const probe = 'n=0; if true; then n=$((n+1)); fi; echo $n'
|
||||||
|
const out = await callRunCommand(ctx, probe)
|
||||||
|
t.ok(out.ok)
|
||||||
|
t.ok(seen.length >= 1)
|
||||||
|
t.ok(seen[0].startsWith(`sh -c '${probe}'`))
|
||||||
|
})
|
||||||
|
|
||||||
test('run_command keeps simple command direct with capture redirection', async (t) => {
|
test('run_command keeps simple command direct with capture redirection', async (t) => {
|
||||||
const { ctx, seen } = makeCtx()
|
const { ctx, seen } = makeCtx()
|
||||||
const out = await callRunCommand(ctx, 'echo hi')
|
const out = await callRunCommand(ctx, 'echo hi')
|
||||||
|
|||||||
Reference in New Issue
Block a user