Dollar Syntax Reference
Version scope: The argv/CommandResult/check/config API is available in 3.1.5. Session settings and managed jobs/deadlines are features available in 5.0.0. Use the canonical API guide to choose examples for your installed version.
Dollar syntax is SSHScript v3.1’s optional shorthand for .spy files. It uses the same Session implementation as the primary Python API, but lets an automation script place $ before a command.
Use Running Commands and Shell Pipelines for libraries, applications, and ordinary Python projects. Use Dollar syntax when concise, shell-like operational steps improve the readability of a standalone script.
Execute commands and read results
$hostname
print($.stdout.strip())
$python3 -c "import sys; sys.stderr.write('problem\\n'); sys.exit(7)"
print($.exitcode) # 7
print($.stderr.strip()) # problem
Each command updates $.stdout, $.stderr, and $.exitcode. Capture the output and status when the values must survive a later command:
stdout, stderr, exitcode = $python3 -c "import sys; print('out'); sys.stderr.write('err\\n')"
Command forms
$hostname
$'printf string-literal'
$r'printf raw-string'
command = "python3 -c \"print('from a variable')\""
$(command, timeout=5)
name = "SSHScript"
$f'printf "Hello, %s\\n" {name}'
Outside persistent consoles, $(...) accepts a nonempty string or a list/tuple of string arguments, just like Session.exec_command(). It returns CommandResult, unpacked as stdout, stderr, exitcode. check=True works locally and remotely. Persistent console commands remain one-line strings. In 4.0 source they also return immutable CommandResult snapshots with three-value unpacking; published 3.1.5 console calls still return two buffers. Input inside enter() remains an interaction, not a completed command result.
Quote dynamic values before inserting them into a shell command:
import shlex
folder = "/tmp/a folder"
$f'mkdir -p {shlex.quote(folder)}'
For argument-preserving one-shot execution, pass an argument list directly:
arguments = ["printf", "%s\n", "hello world"]
$(arguments, check=True)
Automatic shell selection
V3.1 inspects the final command string with quote awareness. Plain commands use argument-preserving mode. Pipelines, redirection, logical operators, assignments, globbing, expansion, and command substitution automatically select a shell.
$printf 'alpha\\nbeta\\n' | grep beta
$VALUE=ready; printf '%s\\n' "$VALUE"
$printf 'report\\n' > /tmp/sshscript-report.txt
$printf 'host: %s\\n' "$(hostname)"
Shell operators inside quotes do not select shell mode. A dollar expression inside single quotes remains literal:
$echo '$HOME'
assert $.stdout.strip() == "$HOME"
Override selection when required:
command = 'python3 -c "import sys; print(sys.argv[1:])" "|" "cat"'
$(command, shell=False)
$("printf 'POSIX shell\\n'", shell=True)
bash_command = (
'[[ -n "$BASH_VERSION" ]] '
'&& printf "%s\\n" "$BASH_VERSION"'
)
$(bash_command, shell="bash")
$(bash_command, shell=True, shell_executable="bash")
shell_executable= chooses the executable used when shell mode is active; it does not by itself force a plain command into shell mode.
On a local Session, shell=False launches the parsed argument vector without a shell. On a remote Session, SSHScript safely re-quotes the vector and sends exec ... through the SSH server’s command shell. Operators remain literal arguments rather than user shell syntax, but a server-side shell still participates.
One $ replaces former $$
Older documents use $$ to force a shell:
$$ls -l | grep '^d'
Write new v3.1 scripts with one Dollar:
$ls -l | grep '^d'
The $$ form remains temporarily compatible but is deprecated and forces shell mode.
Session contexts
The notation is unchanged inside remote and privileged contexts:
$hostname # localhost
with $.connect("ops@example.net"):
$hostname
with $.sudo(password=password):
$systemctl status nginx
Developer tests
The source checkout includes a localhost-only smoke suite:
(cd src/sshscript && python3 sshscript.py unittest/dollar_syntax.spy)
Run that command from the public repository root. For the complete, layout-aware gate, prefer python3 tools/run_checks.py.
It does not load credentials, connect to an SSH server, use an SSH agent, or read a private key. See Contributing and Testing for the unittest wrapper, full release gate, and language integration modes.
Assertions and production command checks
User-written assert statements in .spy files retain normal Python semantics. python -O removes them, including calls inside the assertion. They are useful for illustrative tests, but production scripts must explicitly inspect session.exitcode (or $.exitcode) and handle nonzero status, or use Session.exec_command(..., check=True) on local or remote Sessions to raise subprocess.CalledProcessError after preserving the completed result. SSH, timeout, and transport failures remain exceptions regardless of optimization.
AssertionError was never a supported SSHScript API contract. Package runtime validation now uses explicit exceptions in both normal and optimized modes. See Exceptions and Return Values.
Last Updated: 2026-10-10 19:43:07