Multiline Search¶
By default, ripgrep searches line-by-line, and patterns cannot match across line boundaries. The -U or --multiline flag enables multiline mode, allowing patterns to match text that spans multiple lines.
Basic Usage¶
# Search for "foo" followed by "bar" on the next line
rg -U 'foo\nbar'
# Match patterns spanning multiple lines
rg -U 'struct.*\{.*field'
How Multiline Mode Works¶
When multiline mode is enabled:
- Ripgrep reads entire files into memory instead of processing line-by-line
- The pattern can include
\nto match newlines - The
.metacharacter still does not match newlines by default (see Multiline Dotall Mode) - Use
\p{any}to match any character including newlines
Memory Implications¶
Performance Impact
Multiline mode requires reading entire files into memory, which has significant performance implications:
- Cannot use memory mapping for stdin
- Large files consume more memory
- Slower than line-by-line search for most cases
Automatic Optimization¶
Ripgrep intelligently analyzes your pattern to avoid the memory penalty when possible. If your pattern contains \n but doesn't actually need to match across lines, ripgrep can still use its efficient line-by-line processing.
flowchart LR
Start["Pattern with -U flag"] --> Analysis{"Pattern
Analysis"}
Analysis -->|"Contains \n only"| LineByLine["Line-by-Line
Processing"]
Analysis -->|"Contains . with dotall
or \p{any}"| FullMemory["Full Memory
Loading"]
LineByLine --> Fast["Fast
Low Memory"]
FullMemory --> Slow["Slower
High Memory"]
style LineByLine fill:#e8f5e9
style FullMemory fill:#fff3e0
style Fast fill:#e8f5e9
style Slow fill:#ffebee
Figure: Ripgrep's pattern optimization showing when it avoids the memory penalty.
Patterns that avoid the memory penalty:
# Source: crates/core/flags/defs.rs:4177-4181
# Pattern has \n but doesn't match across line boundaries
rg -U 'foo\nbar' # Each match is on separate lines
Patterns that require full memory loading:
# Pattern needs to span lines using . or \p{any}
rg -U --multiline-dotall 'foo.*bar' # May match across multiple lines
rg -U 'foo\p{any}+bar' # Explicitly matches any character including newlines
Performance Best Practice
When possible, avoid multiline mode entirely. If you can express your search using line-by-line patterns, you'll get much better performance.
When to Use Multiline¶
Use multiline mode when:
- Searching for patterns that span lines (e.g., multi-line log entries)
- Matching code blocks with specific structure
- Finding XML/JSON elements spanning multiple lines
Common Use Cases¶
Multi-line Log Entry Matching¶
Find log entries that span multiple lines, such as stack traces or error blocks:
# Find ERROR entries that include the next line (often a stack trace)
rg -U 'ERROR:.*\n.*at .*'
# Find multi-line JSON log entries
rg -U '\{[^}]*\n[^}]*"level":\s*"error"'
Code Block Searching¶
Finding Function Definitions
Search for multi-line function signatures and bodies:
XML/JSON Element Matching¶
Match structured data that spans multiple lines:
# Find XML elements with specific attributes
rg -U '<user.*\n.*role="admin"'
# Find JSON objects with nested properties
rg -U '\{.*\n.*"status":\s*"active".*\n.*"role"'
Multi-line Text Patterns¶
Matching Across Line Boundaries
Multiline Dotall Mode¶
Even in multiline mode, the . metacharacter does not match newlines by default. To make . match newlines, use the --multiline-dotall flag.
flowchart LR
Pattern["Pattern with .
metacharacter"] --> Mode{"Multiline
Mode?"}
Mode -->|"-U only"| NoDot["Dot does NOT
match newline"]
Mode -->|"-U --multiline-dotall
or (?s)"| YesDot["Dot matches
newline"]
NoDot --> UseAny["Use \p{any}
to match newlines"]
YesDot --> CanSpan["Can match across
line boundaries"]
style NoDot fill:#fff3e0
style YesDot fill:#e8f5e9
style UseAny fill:#e1f5ff
style CanSpan fill:#e8f5e9
Figure: How dotall mode changes . metacharacter behavior in multiline searches.
Using Multiline Dotall¶
Default Behavior
In multiline mode, . still does not match newlines unless you explicitly enable dotall mode.
# Source: tests/multiline.rs:21-25
# This FAILS - . doesn't match \n
rg -U 'world.+detective'
# Source: tests/multiline.rs:28-43
# This SUCCEEDS - . now matches \n
rg -U --multiline-dotall 'world.+detective'
Alternative: Inline Syntax¶
You can enable dotall mode inline using the (?s) flag:
# Enable dotall for the entire pattern
rg -U '(?s)world.+detective'
# Enable dotall for specific part only
rg -U 'world(?s:.+)detective'
Using \p{any}¶
The \p{any} Unicode character class always matches any character including newlines, regardless of dotall mode:
Portable Alternative to Dotall
Using \p{any} is more explicit and doesn't require the --multiline-dotall flag:
See Also¶
- PCRE2 - Advanced regex features and syntax
- Unicode - Unicode character classes like
\p{any} - Performance - Understanding ripgrep's performance characteristics
- Inline Flags - Using flags like
(?s)within patterns