String Literals and Escaping
This guide covers how to properly write string literals, regex patterns, and special characters in JMESPath expressions. Understanding escaping is crucial for working with split(), replace(), regex functions, and any operation involving literal strings.
The Golden Rule
In JMESPath:
- Single quotes
'...'= Identifiers (field names) - Backticks with JSON
`"..."`= String literals
# WRONG - 'hello' is an identifier (looks for a field named "hello")
echo '{"hello": "world"}' | jpx "'hello'"
# null (unless there's a field whose value equals the string "hello")
# RIGHT - `"hello"` is a string literal
echo '{"data": "hello"}' | jpx 'data == `"hello"`'
# true
String Literals Quick Reference
| What you want | JMESPath syntax | Shell example |
|---|---|---|
String hello | `"hello"` | jpx 'length(“hello”)' --null-input |
| String with spaces | `"hello world"` | jpx 'length(“hello world”)' --null-input |
| Empty string | `""` | jpx '@ == “”' --null-input |
Number 42 | `42` | jpx '42+8' --null-input |
| Boolean | `true` or `false` | jpx 'true' --null-input |
| Null | `null` | jpx 'null' --null-input |
Special Characters
Newlines, Tabs, and Escapes
Inside backtick literals, use standard JSON escape sequences:
| Character | JMESPath syntax | Example |
|---|---|---|
| Newline | `"\n"` | split(@, “\n”) |
| Tab | `"\t"` | split(@, “\t”) |
| Carriage return | `"\r"` | replace(@, “\r”, “”) |
| Backslash | `"\\"` | split(@, “\”) |
| Double quote | `"\""` | contains(@, “"”) |
Example: Splitting by Newlines
# Split multi-line text into array
echo '"line1\nline2\nline3"' | jpx 'split(@, `"\n"`)'
# ["line1", "line2", "line3"]
Example: Working with Tabs
# Split TSV (tab-separated values)
echo '"name\tage\tcity"' | jpx 'split(@, `"\t"`)'
# ["name", "age", "city"]
Regex Patterns
Regex functions (regex_match, regex_extract, regex_replace, etc.) need their patterns as string literals.
Regex Quick Reference
| Regex pattern | JMESPath syntax | What it matches |
|---|---|---|
\d+ (digits) | `"\\d+"` | One or more digits |
\w+ (word chars) | `"\\w+"` | Word characters |
\s+ (whitespace) | `"\\s+"` | Whitespace |
[a-z]+ | `"[a-z]+"` | Lowercase letters |
^start | `"^start"` | Starts with “start” |
end$ | `"end$"` | Ends with “end” |
Key insight: Backslash escapes in regex patterns need to be escaped for JSON, so \d becomes \\d inside the backtick literal.
Example: Extract Numbers
echo '"Order #12345"' | jpx 'regex_extract(@, `"\\d+"`)'
# "12345"
Example: Match Email Pattern
echo '"contact@example.com"' | jpx 'regex_match(@, `"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"`)'
# true
Example: Replace Whitespace
echo '"hello world"' | jpx 'regex_replace(@, `"\\s+"`, `" "`)'
# "hello world"
Shell Escaping Layers
When running jpx from a shell, you have multiple escaping layers:
- Shell interprets your command line
- JMESPath parses the expression
- JSON (inside backticks) parses the literal
- Regex engine (for regex functions) interprets the pattern
Shell Quoting Strategies
Single quotes (recommended) - Shell doesn’t interpret anything:
# Best: Use single quotes around the entire expression
echo '{"text": "hello"}' | jpx 'regex_match(text, `"\\w+"`)'
Double quotes - Need to escape backticks and backslashes:
# Harder: Must escape backticks and double backslashes
echo '{"text": "hello"}' | jpx "regex_match(text, \`\"\\\\w+\"\`)"
Recommendation
Always use single quotes around your JMESPath expression when possible:
jpx 'your_expression_here'
This lets you write backticks and backslashes without shell interference.
Common Mistakes
Mistake 1: Using Single Quotes for Strings
# WRONG - 'hello' is an identifier
echo '{"x": "hello"}' | jpx "x == 'hello'"
# RIGHT - use backtick literal
echo '{"x": "hello"}' | jpx 'x == `"hello"`'
Mistake 2: Forgetting Quotes Inside Backticks
# WRONG - `hello` is not valid JSON
jpx '`hello`' --null-input
# RIGHT - strings need quotes inside backticks
jpx '`"hello"`' --null-input
Mistake 3: Over-escaping Regex Patterns
# WRONG - too many backslashes
echo '"abc123"' | jpx 'regex_extract(@, `"\\\\d+"`)'
# RIGHT - just escape once for JSON
echo '"abc123"' | jpx 'regex_extract(@, `"\\d+"`)'
Mistake 4: Confusing Identifier vs String
# This looks for field named "name" - CORRECT
echo '{"name": "Alice"}' | jpx 'name'
# "Alice"
# This compares against literal string - CORRECT
echo '{"name": "Alice"}' | jpx 'name == `"Alice"`'
# true
# This looks for field named by VALUE of 'name' field - WRONG (usually)
echo '{"name": "Alice"}' | jpx "'name'"
# null (looks for field "name" on string "Alice")
MCP Server Context
When using jpx through the MCP server (e.g., with Claude), there’s an additional JSON encoding layer. The MCP server handles this automatically, but be aware:
- Expressions are passed as JSON strings
- The server unescapes before evaluating
- When writing expressions in MCP tool calls, you typically don’t need extra escaping
Example MCP Tool Call
{
"name": "jpx_query",
"arguments": {
"expression": "split(@, `\"\\n\"`)",
"data": "line1\nline2\nline3"
}
}
The MCP server handles the JSON string escaping, so \" becomes " and \\n becomes \n in the actual expression.
Debugging Tips
-
Use
--null-inputto test expressions without needing input data:jpx '`"test\\nstring"`' --null-input -
Start simple - verify your literal works before using it in a function:
# First, check the literal jpx '`"\\d+"`' --null-input # "\d+" # Then use it echo '"abc123"' | jpx 'regex_extract(@, `"\\d+"`)' -
Check the AST for complex expressions:
jpx --ast 'split(@, `"\n"`)'
Summary
| Context | Syntax | Example |
|---|---|---|
| Field access | fieldname | user.name |
| String literal | `"string"` | `"hello"` |
| Newline in string | `"\n"` | split(@, “\n”) |
| Regex digit | `"\\d+"` | regex_match(@, “\d+”) |
| Comparison | field == “value”`` | status == “active”`` |