7 Shell Commands🔗ℹ
The recspecs/shell module provides tools for testing interactive
shell commands, inspired by the Unix expect tool. Use
expect/shell for transcript-based tests. The module also exposes
experimental pattern-matching helpers for lower-level interactive control.
7.1 Basic Shell Testing🔗ℹ
| (expect/shell cmd-expr | | [#:strict? strict?-expr #f] | | [#:status status-expr #f] | | [#:port port-expr (quotestdout)] | | [#:env env-expr #f] | | [#:match match-expr (quoteequal)] | | expected-str ...) |
|
Run cmd-expr as a subprocess and compare the interaction
against expected-str .... Lines in the expectation that begin
with > are sent to the process as input (without the prompt).
The command’s responses are captured and the full transcript is checked
against the expectation.
#:status accepts an exact integer, such as 0, to check
the subprocess exit code. #:port accepts (quote stdout),
(quote stderr), or (quote both). #:env accepts an
environment-variables? value. #:match accepts
(quote equal), (quote contains), or (quote regexp).
| #:lang at-exp racket |
| (require recspecs/shell) |
| (expect/shell "cat" |
| "> hi""\n" |
| "hi""\n" |
| "> there""\n" |
| "there") |
7.2 Experimental Pattern Helpers🔗ℹ
The pattern interface is experimental. Prefer expect/shell for tests
that can be represented as a transcript. The lower-level pattern helpers are
useful for testing pattern parsing and for experimenting with interactive
control, but the current implementation does not implement timeout or EOF
pattern matching, and a pattern that never matches can block.
expect/shell/patterns accepts exact, regexp, and glob patterns plus
actions that send input, continue, retry, raise an error, or call a custom
procedure:
| (expect/shell/patterns cmd-expr | | [#:strict? strict?-expr #f] | | [pattern action] ...) |
|
| |
| pattern | | = | | string-expr | | | | | | | (exact string-expr) | | | | | | | (regex regex-expr) | | | | | | | (glob glob-string-expr) | | | | | | | | action | | = | | (send-input text-expr) | | | | | | | continue | | | | | | | retry | | | | | | | (error message-expr) | | | | | | | procedure-expr |
|
Runs cmd-expr as an interactive subprocess and processes
pattern/action pairs in order. Each pattern is matched against accumulated
output; when it matches, the action is executed. Regex captures are available
for substitution in (send-input text-expr) as $0,
$1, and so on.
7.3 Pattern Matching Reference🔗ℹ
| (match-pattern pattern text vars) | | → | | |
|
| pattern : pattern? |
| text : string? |
| vars : list? |
Tests whether pattern matches text. Returns three values:
whether the pattern matched, updated variable list with any captures, and the text.
This function underlies the pattern matching in expect/shell/patterns
and can be used directly for testing pattern logic.
| (define-values (matched? vars text) |
| (match-pattern (pattern-regex #rx"port: ([0-9]+)") "port: 8080" '())) |
7.4 Pattern and Action Structures🔗ℹ
The pattern-based shell automation is built on the following structures, which can be
used directly for advanced scenarios:
| (struct | | pattern-action (pattern action vars) |
|
| #:extra-constructor-name make-pattern-action) |
| pattern : pattern? |
| action : action? |
| vars : list? |
Combines a pattern with its corresponding action. The vars field stores
captured variables from previous pattern matches.
|
| #:extra-constructor-name make-pattern-exact) |
| text : string? |
Matches exact string content within the output.
|
| #:extra-constructor-name make-pattern-regex) |
| regex : regexp? |
Matches using regular expressions and captures groups for variable substitution.
| (struct | | pattern-glob (pattern) |
|
| #:extra-constructor-name make-pattern-glob) |
| pattern : string? |
Matches using glob patterns with * and ? wildcards.
| (struct | | action-send-text (text) |
|
| #:extra-constructor-name make-action-send-text) |
| text : string? |
Sends the specified text to the subprocess as input.
|
| #:extra-constructor-name make-action-continue) |
Proceeds to the next pattern in the sequence.
|
| #:extra-constructor-name make-action-retry) |
Retries the current pattern without advancing.
| (struct | | action-error (message) |
|
| #:extra-constructor-name make-action-error) |
| message : string? |
Raises an error with the specified message.
|
| #:extra-constructor-name make-action-proc) |
| proc : procedure? |
Executes a custom procedure with signature (-> shell-session? list? symbol?).
| (shell-run-patterns | | cmd | | | | | | | | patterns | | | | | | | [ | #:timeout timeout]) | | → | | void? |
|
| cmd : (or/c string? (listof string?)) |
| patterns : (listof pattern-action?) |
| timeout : number? = 30 |
Low-level function that runs the pattern-based shell interaction. This function
underlies expect/shell/patterns and can be used for programmatic control.
| (shell-run-patterns "bash" |
| (list (pattern-action (pattern-exact "$") |
| (action-send-text "echo test") |
| '()) |
| (pattern-action (pattern-exact "test") |
| (action-send-text "exit") |
| '()))) |
7.5 Best Practices🔗ℹ
Use specific patterns to avoid false matches: prefer (exact "$ ") over "$"
Use continue judiciously to handle intermediate output
Capture important values with regex patterns for reuse
Test pattern logic in isolation using match-pattern
Enable verbose mode during development for better visibility
Consider the order of patterns carefully: more specific patterns should come before general ones