2.1 The eval Command & Core Evaluation Functions
Key Takeaways
- The eval command evaluates mathematical, string, comparison, conditional, and null-handling expressions per event at search time, writing results to a new or existing field without modifying _raw.
- String manipulation functions like len(), substr(), lower(), upper(), and replace() allow granular parsing and normalization, with substr() utilizing 1-based indexing.
- Comparison and conditional functions (if(), case(), validate()) enable dynamic branching logic, where case() evaluates pairs sequentially and validate() returns an error string on the first false condition.
- Mathematical functions such as round(X, [Y]), ceil(X), and floor(X) control numeric precision and rounding behavior, while arithmetic operations handle null values by returning null.
- Null handling functions (isnull(), isnotnull(), coalesce()) detect missing values and perform fallback selection across alternative fields for log schema normalization.
2.1 The eval Command & Core Evaluation Functions
Quick Answer: The
evalcommand calculates an expression for every incoming event and assigns the resulting value to a destination field at search time. It operates as a streaming command in memory, leaving raw indexed data (_raw) untouched. Theevalcommand supports mathematical operators, string functions (len,substr,lower,upper,replace), conditional branching (if,case,validate), numeric rounding (round,ceil,floor), and null resolution (coalesce,isnull,isnotnull). String literals require double quotes ("..."), field names are unquoted and strictly case-sensitive, and the dot (.) is Splunk's dedicated concatenation operator. Note that+is the documented exception among arithmetic operators: it adds two numbers or concatenates two strings.
1. Architectural Foundations of the eval Command
In the Splunk search processing pipeline, the eval command serves as the primary mechanism for row-level data transformation, dynamic metric calculation, conditional classification, and field normalization. Mastering eval syntax, quoting semantics, and built-in functions is one of the most heavily tested areas on the Splunk Core Certified Power User examination.
+-----------------------+ +-------------------------------+ +-------------------------+
| Incoming Event Stream | ---> | eval dest_field = <expression>| ---> | Transformed Stream |
| bytes=1048576, ms=450 | | (e.g., MB = bytes/1024/1024) | | bytes, ms, MB=1.00 |
+-----------------------+ +-------------------------------+ +-------------------------+
Core Operational Characteristics:
- Event-Level Streaming Execution:
evalis a streaming command. It evaluates expressions on an event-by-event basis as records pass through the search head memory pipeline without requiring historical buffering or global sorting. - Search-Time Immutability:
evalnever modifies the underlying immutable data stored on indexers (_rawor TSIDX index files). All calculated fields exist exclusively in memory for the duration of the search lifecycle. - Destination Field Behavior: If the specified destination field already exists in an event,
evaloverwrites its value with the result of the expression. If the destination field does not exist,evaldynamically creates it and appends it to the event's field list. - Sequential Expression Chaining: You can define multiple field assignments within a single
evalcommand by separating assignments with commas. Splunk processes chained assignments sequentially from left to right, allowing downstream expressions to immediately reference fields calculated earlier in the same statement.
`-- Sequential evaluation chaining: latency_sec is calculated first, then consumed by latency_tier`
... | eval latency_sec = response_time_ms / 1000,
latency_tier = if(latency_sec < 1.0, "OPTIMAL", "DEGRADED")
Strict Quoting Rules in eval Expressions
Understanding how Splunk's SPL parser distinguishes between literals, field references, and special identifiers is vital for writing error-free queries:
| Token Type | Syntax Rule | Example SPL | Parsing Interpretation |
|---|---|---|---|
| String Literals | Must be enclosed in double quotes ("...") | eval env = "Production" | The static string text "Production" is assigned to env. |
| Field References | Must be unquoted | eval total_kb = bytes / 1024 | Reads the current value of the field bytes from each event. |
| Special Field Names | Must be enclosed in single quotes ('...') | eval load = 'cpu-usage%' * 1.2 | Allows field names containing hyphens, spaces, periods, or symbols. |
| Numeric Constants | Must be unquoted | eval rate = 0.0825 | Interpreted directly as an integer or floating-point number. |
[!WARNING] Critical Exam Trap: If you execute
| eval environment = productionwithout double quotes aroundproduction, Splunk interpretsproductionas a field name. If no field namedproductionexists in the event, the new fieldenvironmentevaluates tonull. To assign a literal string, you must write| eval environment = "production".
2. Core String Manipulation Functions
Splunk provides a comprehensive suite of string functions designed to extract sub-elements, calculate lengths, standardize casing, and perform regex substitutions.
STRING MANIPULATION IN EVAL
│
┌───────────────────────────┼───────────────────────────┐
▼ ▼ ▼
Length & Slicing Casing & Cleanup Pattern Replacement
• len(str) • lower(str) • replace(str, regex, sub)
• substr(str, start, len) • upper(str) • trim(str, [chars])
len(X)
Returns the integer character count of string field X. If X is non-existent or null, len() returns null.
... | eval password_length = len(user_password)
substr(X, Y, [Z])
Extracts a substring from string X starting at character position Y (using 1-based indexing) for an optional character length Z. If Z is omitted, substr() extracts all remaining characters through the end of the string. Negative values for Y indicate an offset starting from the end of the string.
`-- Extract first 3 characters (area code) from phone number`
... | eval area_code = substr(phone_number, 1, 3)
`-- Extract the last 4 characters of an account number`
... | eval account_suffix = substr(account_id, -4)
[!IMPORTANT] 1-Based Indexing Rule: Unlike languages like C, Java, or Python which use 0-based indexing, Splunk's
substr()function is 1-based. Insubstr("Splunk", 1, 2), index 1 corresponds to"S", yielding"Sp".
lower(X) and upper(X)
Converts all alphabetic characters in string X to lowercase or uppercase, respectively. These functions are critical for normalizing divergent field values before executing group-by aggregations or case-sensitive comparisons.
... | eval normalized_user = lower(username), alert_status = upper(raw_status)
replace(X, Y, Z)
Scans string X for substrings matching the regular expression Y and replaces all matches with the replacement string Z. Capture groups (e.g., \1, \2) can be referenced within Z.
`-- Strip domain suffix from fully qualified hostnames`
... | eval short_host = replace(host, "\.corp\.example\.com$", "")
`-- Mask middle 6 digits of a 10-digit credit card string`
... | eval masked_card = replace(cc_num, "^(\d{4})\d{6}(\d{4})$", "\1******\2")
trim(X, [Y]), ltrim(X, [Y]), and rtrim(X, [Y])
Strips leading and trailing characters from string X. If the optional character set Y is omitted, it defaults to stripping whitespace characters (spaces, tabs, newlines).
`-- Strip leading and trailing slashes from URI paths`
... | eval clean_uri = trim(uri_path, "/")
String Concatenation: Dot (.) vs. Plus (+)
Splunk's operator table lists . as the concatenation operator, and the dot is what every official example uses. Write it that way:
`-- Canonical SPL concatenation`
... | eval full_endpoint = protocol . "://" . host . ":" . port . uri_path
Be careful with the widely repeated myth that + "returns null on strings." Splunk's own documentation says the opposite: "with the exception of addition, arithmetic operations might not produce valid results if the values are not numerical," and "when concatenating values, Splunk software reads the values as strings, regardless of the value." In practice + concatenates whenever its operands are not numeric:
`-- This does NOT return null. It concatenates: "Jane Doe"`
... | eval full_endpoint = firstName + " " + lastName
The real hazard runs the other direction: + silently switches meaning based on the data. If both operands look numeric, "0001" + "0002" adds to 3; if they do not, it concatenates to 00010002. Use . when you mean concatenation and tonumber() when you mean arithmetic, so the intent never depends on the data.
3. Comparison and Multi-Branch Conditional Functions
Conditional evaluation allows power users to build dynamic categorization tags, assign severity levels, and implement business routing rules directly within the pipeline.
+-----------------------------------------------------------------------------------------+
| CONDITIONAL BRANCHING LOGIC IN EVAL |
+-----------------------------------------------------------------------------------------+
| if(predicate, true_val, false_val) --> Single binary condition (if-then-else) |
+-----------------------------------------------------------------------------------------+
| case(c1, v1, c2, v2, ..., true(), def) --> Sequential multi-branch rule evaluation |
+-----------------------------------------------------------------------------------------+
| validate(c1, e1, c2, e2, ...) --> Data validation (returns error of FIRST failure)|
+-----------------------------------------------------------------------------------------+
if(predicate, true_value, false_value)
Evaluates a single boolean condition (predicate). If the condition evaluates to true, if() returns true_value; otherwise, it returns false_value.
... | eval http_category = if(status >= 400, "ERROR", "SUCCESS")
case(condition1, value1, condition2, value2, ..., [true(), default_value])
Evaluates multiple condition-value pairs sequentially from left to right. It returns the value associated with the first condition that evaluates to true and immediately halts evaluation (short-circuiting). If no conditions evaluate to true and no default condition is provided, case() returns null.
... | eval risk_score = case(
status == 500 OR status == 503, "CRITICAL",
status == 401 OR status == 403, "HIGH",
status == 404, "MEDIUM",
status == 200, "LOW",
true(), "UNKNOWN"
)
[!TIP] Power User Best Practice: Always terminate
case()statements withtrue(), "<default_value>"(or1==1, "<default_value>") as the final fallback pair. This ensures that unhandled edge cases or unexpected log values are explicitly classified rather than silently becomingnull.
validate(condition1, error1, condition2, error2, ...)
Designed specifically for data hygiene and schema validation. It evaluates conditions sequentially and returns the error string associated with the first condition that evaluates to FALSE. If all conditions evaluate to true, validate() returns null.
`-- Identifies why an event failed data formatting standards`
... | eval data_error = validate(
isnotnull(clientip), "Missing Client IP",
isnum(status), "Status is non-numeric",
status >= 100 AND status <= 599, "Status code out of HTTP range"
)
| where isnotnull(data_error)
match(X, Y) and like(X, Y)
match(string, regex): Returns booleantrue(1) if the regular expressionYmatches stringX; otherwisefalse(0).like(string, pattern): Evaluates SQL-style wildcard patterns where%matches any number of characters and_matches a single character.
... | eval is_admin = if(match(user, "(?i)^admin_"), "YES", "NO"),
is_corp_ip = if(like(clientip, "10.200.%.%"), 1, 0)
4. Mathematical and Numeric Evaluation Functions
Splunk provides built-in numeric functions to handle rounding, precision adjustments, and mathematical transformations:
| Function | Signature | Operational Description | Input Example | Output |
|---|---|---|---|---|
round(X, [Y]) | round(num, [decimals]) | Rounds X to Y decimal places (defaults to integer 0 decimals if Y is omitted). | round(3.14159, 2)<br>round(8.75) | 3.14<br>9 |
ceil(X) | ceil(num) | Ceiling: returns the smallest integer greater than or equal to X. | ceil(4.12)<br>ceil(-2.8) | 5<br>-2 |
floor(X) | floor(num) | Floor: returns the largest integer less than or equal to X. | floor(4.89)<br>floor(-2.1) | 4<br>-3 |
abs(X) | abs(num) | Returns the absolute value of numeric expression X. | abs(-45.2) | 45.2 |
min(X, Y, ...) | min(n1, n2, ...) | Returns the minimum numeric value among all argument expressions. | min(12, 5, 29) | 5 |
max(X, Y, ...) | max(n1, n2, ...) | Returns the maximum numeric value among all argument expressions. | max(12, 5, 29) | 29 |
pow(X, Y) | pow(base, exp) | Computes X raised to the power of Y ($X^Y$). | pow(2, 8) | 256 |
sqrt(X) | sqrt(num) | Returns the square root of non-negative number X. | sqrt(144) | 12 |
Handling Numeric Edge Cases & Division by Zero
- Division by Zero: When an arithmetic expression encounters division by zero (e.g.,
eval ratio = total / countwherecount = 0), Splunk does not throw a search error. The target field evaluates cleanly tonull. - Non-Numeric Arithmetic: Attempting arithmetic operations on fields containing non-numeric strings results in
null.
5. Null Identification and Normalization Functions
In enterprise environments, logs from disparate systems frequently record identical attributes under different field names, or omit fields entirely.
+-----------------------------------------------------------------------------------------+
| NULL RESOLUTION WITH COALESCE |
+-----------------------------------------------------------------------------------------+
| Heterogeneous Sources: |
| Source A (Windows): Account_Name = "jsmith" | src_user = null | username = null |
| Source B (Linux): Account_Name = null | src_user = null | username = "root" |
| |
| SPL Transformation: |
| | eval user_id = coalesce(Account_Name, username, src_user, "UNKNOWN") |
| |
| Result: |
| Source A -> user_id = "jsmith" |
| Source B -> user_id = "root" |
+-----------------------------------------------------------------------------------------+
isnull(X) and isnotnull(X)
isnull(X): Returns booleantrue(1) if fieldXdoes not exist in the event or contains a null value; otherwisefalse(0).isnotnull(X): Returns booleantrue(1) if fieldXexists and contains a non-null value; otherwisefalse(0).
... | eval ip_status = if(isnull(client_ip), "UNRESOLVED", "RESOLVED")
coalesce(field1, field2, field3, ...)
Evaluates the arguments in order from left to right and returns the value of the first non-null argument. If all provided arguments evaluate to null, coalesce() returns null.
`-- Normalize heterogeneous IP field names across firewall, proxy, and web logs`
... | eval canonical_ip = coalesce(src_ip, clientip, c_ip, remote_addr, "0.0.0.0")
null()
Returns a null value. This function is typically used in conditional branches to explicitly discard or undefine a field under specific conditions.
`-- Strip internal test IPs from downstream analytics`
... | eval public_ip = if(like(clientip, "10.%"), null(), clientip)
6. Comprehensive eval Function Reference
The following reference matrix summarizes the core functions tested on the Power User exam:
| Function Signature | Category | Purpose & Description | SPL Example | Output |
|---|---|---|---|---|
len(X) | String | Returns integer length of string X | len("Splunk") | 6 |
substr(X, Y, [Z]) | String | Substring starting at 1-based index Y for length Z | substr("Enterprise", 1, 5) | "Enter" |
lower(X) | String | Converts string X to lowercase | lower("Admin") | "admin" |
upper(X) | String | Converts string X to uppercase | upper("warn") | "WARN" |
replace(X, Y, Z) | String | Regex replacement of pattern Y in X with Z | replace("v1.2.3", "^v", "") | "1.2.3" |
trim(X, [Y]) | String | Strips whitespace/characters from ends of X | trim(" test ") | "test" |
if(C, T, F) | Conditional | Evaluates boolean C; returns T if true, F if false | if(status==200, 1, 0) | 1 or 0 |
case(C1,V1,...) | Conditional | Multi-branch evaluation; returns first true value | case(code==0, "OK", true(), "ERR") | "OK" or "ERR" |
validate(C1,E1,...) | Conditional | Returns error string of first FALSE condition | validate(port>0, "Invalid Port") | null or "Invalid Port" |
round(X, [Y]) | Mathematical | Rounds X to Y decimals (default 0) | round(45.678, 2) | 45.68 |
ceil(X) | Mathematical | Smallest integer greater than or equal to X | ceil(3.01) | 4 |
floor(X) | Mathematical | Largest integer less than or equal to X | floor(3.99) | 3 |
abs(X) | Mathematical | Absolute value of numeric expression X | abs(-105) | 105 |
isnull(X) | Null Logic | Returns true (1) if X is null | isnull(user_session) | 1 or 0 |
isnotnull(X) | Null Logic | Returns true (1) if X is non-null | isnotnull(host) | 1 or 0 |
coalesce(A, B, ...) | Null Logic | Returns value of first non-null argument | coalesce(src, client, "N/A") | Value or "N/A" |
7. Complex Nested Expressions in Production SPL
In real-world enterprise searches, power users combine multiple eval functions into nested expressions to perform comprehensive data sanitization and categorization in a single pipeline stage:
index=web sourcetype=access_combined
| eval canonical_user = lower(trim(coalesce(user, auth_user, account, "anonymous"))),
response_sec = round(response_time_ms / 1000, 3),
status_tier = case(
status >= 500, "5xx_SERVER_ERROR",
status >= 400, "4xx_CLIENT_ERROR",
status >= 300, "3xx_REDIRECT",
status >= 200, "2xx_SUCCESS",
true(), "OTHER_STATUS"
),
is_slow = if(response_sec > 2.500 AND status_tier != "2xx_SUCCESS", 1, 0)
| stats count, avg(response_sec) as mean_latency by status_tier, is_slow
Explanation of Execution:
canonical_userresolves the first non-null username across three field variations, strips surrounding whitespace, and converts the string to lowercase.response_secconverts millisecond timings into decimal seconds, rounded cleanly to 3 decimal places.status_tierclassifies the event based on HTTP response ranges using sequentialcase()evaluation with a catch-alltrue()condition.is_slowflags requests taking longer than 2.5 seconds that also resulted in errors.
8. Common Exam Traps & Pitfalls
- Case Sensitivity in Field Names: Field names within
evalexpressions are strictly case-sensitive, and Splunk documents that the entire eval expression is case-sensitive.eval x = Status + 1will not read the fieldstatus. Write commands and functions in lowercase, as Splunk's documentation does throughout. - Unquoted Literal Assignment: Writing
| eval role = adminassigns the value of the fieldadmin(oftennull), whereas| eval role = "admin"assigns the string literal"admin". - The
+Ambiguity:| eval name = first_name + " " + last_namedoes not return null — Splunk treats addition as the one arithmetic operator that also concatenates strings, so it produces"Jane Doe". The trap is that+changes meaning when the operands happen to be numeric. Use the dedicated concatenation operator:| eval name = first_name . " " . last_name. - Missing Default in
case(): If none of the conditions in acase()statement evaluate to true and notrue(), "default"pair is provided, the destination field is assignednull.
A Splunk Power User needs to create a normalized field named user_tier. The requirement states: if account_level is null, use the value from default_level; if both are null, assign the string literal 'STANDARD'. Which eval expression correctly accomplishes this?
An analyst executes the following search pipeline on an event stream:
... | eval raw_cost = 42.871, rounded_cost = round(raw_cost, 1), ceil_cost = ceil(raw_cost), floor_cost = floor(raw_cost)
What are the resulting values for rounded_cost, ceil_cost, and floor_cost?
What is the result of executing the SPL expression | eval full_name = firstName + " " + lastName when firstName="Jane" and lastName="Doe"?