On this page:
7.1 Basic Shell Testing
expect/  shell
7.2 Experimental Pattern Helpers
expect/  shell/  patterns
7.3 Pattern Matching Reference
match-pattern
7.4 Pattern and Action Structures
pattern-action
pattern-exact
pattern-regex
pattern-glob
action-send-text
action-continue
action-retry
action-error
action-proc
shell-run-patterns
7.5 Best Practices

7 Shell Commands🔗ℹ

 (require recspecs/shell) package: recspecs-lib

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🔗ℹ

syntax

(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:

syntax

(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🔗ℹ

procedure

(match-pattern pattern text vars)  
boolean? list? string?
  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

(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.

struct

(struct pattern-exact (text)
    #:extra-constructor-name make-pattern-exact)
  text : string?
Matches exact string content within the output.

struct

(struct pattern-regex (regex)
    #:extra-constructor-name make-pattern-regex)
  regex : regexp?
Matches using regular expressions and captures groups for variable substitution.

struct

(struct pattern-glob (pattern)
    #:extra-constructor-name make-pattern-glob)
  pattern : string?
Matches using glob patterns with * and ? wildcards.

struct

(struct action-send-text (text)
    #:extra-constructor-name make-action-send-text)
  text : string?
Sends the specified text to the subprocess as input.

struct

(struct action-continue ()
    #:extra-constructor-name make-action-continue)
Proceeds to the next pattern in the sequence.

struct

(struct action-retry ()
    #:extra-constructor-name make-action-retry)
Retries the current pattern without advancing.

struct

(struct action-error (message)
    #:extra-constructor-name make-action-error)
  message : string?
Raises an error with the specified message.

struct

(struct action-proc (proc)
    #:extra-constructor-name make-action-proc)
  proc : procedure?
Executes a custom procedure with signature (-> shell-session? list? symbol?).

procedure

(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