Skip to content

Matching Behavior

This page explains how runok parses commands and matches them against patterns.

runok does not rewrite or preprocess patterns. The way you write a rule is exactly how it is parsed and matched:

  • No implicit splitting or joining. Tokens are separated by spaces, and =-joined values stay as a single token.
  • Rules are self-contained. You can understand a rule’s behavior by reading it alone — definitions do not change how a pattern is parsed.
# "-Denv=prod" is a single token — matched as-is
- deny: 'java -Denv=prod *'
# Matches: java -Denv=prod -jar app.jar
# Does NOT match: java -Denv staging -jar app.jar
# "-X" and "POST" are separate tokens — matched as flag and value
- deny: 'curl -X POST *'
# Matches: curl -X POST https://example.com

When a pattern contains a flag followed by a value, runok infers that the flag takes a value argument. This inference is used when parsing the actual command to correctly associate values with their flags.

# Pattern: curl -X|--request POST *
# Inferred flag schema: -X and --request take a value
- deny: 'curl -X|--request POST *'

With this inferred schema, the command curl -X POST https://example.com is parsed as:

  • -X — flag
  • POST — value of -X
  • https://example.com — positional argument

Without this inference, POST would be treated as a positional argument rather than a flag value.

Flags inside optional groups are also included in the inferred schema:

# Both -o/--output and -X/--request are inferred as value flags
- allow: 'curl [-o|--output *] -X|--request GET *'

Flags (tokens starting with -) in patterns are matched regardless of their position in the command:

- allow: 'git push -f|--force *'
CommandResult
git push --force origin mainMatches
git push origin --force mainMatches
git push origin main --forceMatches

This applies to both standalone flags (alternation) and flag-value pairs. The matcher scans the entire command token list to find a matching flag, removes it, and continues matching the remaining tokens.

Tokens that do not start with - are matched in order:

- allow: 'git push origin main'
CommandResult
git push origin mainMatches
git push main originDoes not match

A backslash (\) in a pattern escapes the following character. During matching, the backslash is stripped and the remaining character is compared literally. This is useful for characters that have special meaning in shells, such as ;:

# \; in the pattern matches ; in the command
- "find * -exec <cmd> \\;|+"

The shell resolves \; to ; before runok sees the command, so the pattern’s \; (after unescape) matches the command’s ;.

Combined short flags like -am are not split into individual flags — they are matched as a single token, exactly as written:

- deny: 'git commit -m *'
CommandResultReason
git commit -m "fix bug"Matches-m matches directly
git commit -am "fix bug"Does not match-am is a different token than -m

If you want to match -am, write it explicitly:

- deny: 'git commit -am *'

To prevent pathological patterns (such as many consecutive wildcards) from causing excessive computation, matching is limited to 10,000 steps. Patterns that exceed this limit fail to match.