Native scripts and script files¶
Use SessionScript when shell syntax is the task. Choose the backend entry;
the library never translates script languages.
- Run a pipeline that selects
apple. Bash usesprintfandgrep, PowerShell usesWhere-Object, and cmd usesfindstr. These are native tools/operators, not portableProcessCommandarguments. - Assign a native variable in one call and read it in another. The interpreter stays alive, so the value survives. Bash and PowerShell also preserve native functions and aliases; cmd has no equivalent function/alias capability.
- Write a complete trusted
.sh,.ps1, or.cmdfile in the temporary workspace, read its exact source, and execute it in the existing session.
The third example runs file contents, not a separate script interpreter:
file-relative variables such as PowerShell $PSScriptRoot, Bash $0, and cmd
%~dp0 do not identify the original file. For an independent script process,
use ProcessCommand('bash', ('path/to/script.sh',)) on Linux or
ProcessCommand('pwsh', ('-NoProfile', '-File', 'path/to/script.ps1')) on Windows.
For a cmd batch file use native call syntax in SessionScript, with a trusted,
properly quoted path. Child-process state changes do not update the parent shell.
Scripts are trusted code, not a sandbox. Their state changes are not rolled back
on failure. Do not use the reserved sn_ namespace, Bash descriptor 9, or terminate
the persistent interpreter with exit. Keep caller data in structural arguments.
Full example¶
File: examples/04-scripts.py.
python examples/04-scripts.py bash
On Windows replace bash with powershell or cmd.
"""Run native syntax, preserve shell variables, and execute a trusted script file."""
import asyncio
import os
import sys
from pathlib import Path
from tempfile import TemporaryDirectory
from shell_next import Backend, SessionConfig, SessionScript, use_shell_session
async def main(backend: Backend) -> None:
# The three entries are native programs with the same observable intent.
assign, read, pipeline, suffix = {
Backend.BASH: (
"demo_answer=42",
'printf "%s\\n" "$demo_answer"',
"printf 'apple\\npear\\n' | grep apple",
".sh",
),
Backend.POWERSHELL: (
"$demo_answer = 42",
"Write-Output $demo_answer",
"'apple', 'pear' | Where-Object { $_ -eq 'apple' }",
".ps1",
),
Backend.CMD: (
'set "demo_answer=42"',
"echo %demo_answer%",
"(echo apple&echo pear) | findstr apple",
".cmd",
),
}[backend]
with TemporaryDirectory(prefix="shell-next-script-") as directory:
config = SessionConfig(backend=backend, cwd=directory, startup_timeout=30)
async with use_shell_session(config) as shell:
# 1. Operators and shell built-ins belong in SessionScript.
result = await shell.run(SessionScript(pipeline), check=True)
assert result.stdout_str().strip() == "apple"
# 2. A variable assigned in one call survives into the next call.
await shell.run(SessionScript(assign), check=True)
result = await shell.run(SessionScript(read), check=True)
assert result.stdout_str().strip() == "42"
# 3. Load a trusted file as native source in the existing session.
path = Path(directory) / ("demo" + suffix)
path.write_text(assign + "\n" + read + "\n", encoding="utf-8")
result = await shell.run(SessionScript(path.read_text(encoding="utf-8")), check=True)
assert result.stdout_str().strip() == "42"
print(result.stdout_str(), end="")
if __name__ == "__main__":
selected = sys.argv[1] if len(sys.argv) > 1 else ("cmd" if os.name == "nt" else "bash")
asyncio.run(main(Backend(selected)))