Splunk Search

How to force "eval" to cast an expression as numeric value?

Lowell
Super Champion

Let's say you have two fields like so:

a=0001L
b=0002L

What's the best way to force the eval command to see these as numeric fields so that you can add these two values together. It seems like you should be able to simply say something like:

... | eval c=rtrim(a,"L") + rtrim(b,"L")

However, "c" ends up with the value "00010002" instead of 3 because within the scope of that individual eval splunk thinks the output of both rtrim as strings and not as numeric values.

To quickly test this yourself, you can run this contrived search command:

* | head 1 | a="0001L" | eval b="0002L" | eval c=rtrim(a,"L") + rtrim(b,"L") | fields a b c

So the question is this:

Is there anyway to force eval to cast the output of an expressions to a numeric value, so that "+" becomes a mathematical operation and not a string concatenation?


Yes, I realize that simply breaking this into multiple evals solves this problem, like so:

...  eval _a=rtrim(a,"L") | eval _b=rtrim(b,"L") | eval c= _a+_b

However, this does NOT work for my use case. I am attempting to write an eval-based macro expression which must be a single eval, not a series of evals. Therefore, all the work has to be done in a single eval.

I guess I'm looking for counterpart of tostring. Is there some an undocumented "tonumber()" or similar function?

1 Solution

mitch
Explorer

Yeah, it looks like a tonumber() function is a badly needed addition to the language. I'm going to file a bug report right now.

The one (gross) workaround that I can think of is to abuse the strptime() time parser. This would only work on non-negative integers, but it might be enough for your immediate issue:

$ splunk search '* | head 1 | eval a="0001L" | eval b="0002L" | eval c=strptime(rtrim(a,"L"),"%s") + strptime(rtrim(b,"L"),"%s") | table a b c'
  a     b      c
----- ----- --------
0001L 0002L 3.000000

View solution in original post

Ellen
Splunk Employee
Splunk Employee

In 4.1.5, the eval command now includes a tonumber() function.

For reference: http://www.splunk.com/base/Documentation/4.1.5/SearchReference/CommonEvalFunctions

mitch
Explorer

Yeah, it looks like a tonumber() function is a badly needed addition to the language. I'm going to file a bug report right now.

The one (gross) workaround that I can think of is to abuse the strptime() time parser. This would only work on non-negative integers, but it might be enough for your immediate issue:

$ splunk search '* | head 1 | eval a="0001L" | eval b="0002L" | eval c=strptime(rtrim(a,"L"),"%s") + strptime(rtrim(b,"L"),"%s") | table a b c'
  a     b      c
----- ----- --------
0001L 0002L 3.000000

Lowell
Super Champion

Thanks for filing a request. I found a workaround for my specific needs using relative_time(). But there are certainly other cases where such a solution wouldn't work, so a tonumber(), or whatever it ends up being called would be greatly appreciated.

0 Karma

ftk
Motivator

I agree -- badly needed.

0 Karma

V_at_Splunk
Splunk Employee
Splunk Employee

If the values really are all single digits with 0s prepended, I have (a very ugly) solution for you. The one function that maps string to num, is len. Ready? First, strip the 0s. Then, replace 1 with a single x, 2 with xx, and so forth. And finally, we can invoke len on the resulting string (xx maps to 2😞

* | head 1 | eval a="0001L" | eval b="0002L" | eval c=len(replace(replace(replace(rtrim(a,"L"), "0", ""), "1", "x"), "2", "xx")) + len(replace(replace(replace(rtrim(b,"L"), "0", ""), "1", "y"), "2", "yy")) | table a b c

gives

  a     b   c
----- ----- -
0001L 0002L 3

Lowell
Super Champion

+1. Just for the craziness of this solution. (I do wonder how far this would stretch. Is the eval handled in a stack-based way, would you eventual end up with a stack overflow?...)

Lowell
Super Champion

Wow. That's hilarious. But no, in my particular use case I'm looking at a time field. So mapping 0-23 and 0-59 within a single eval using this approach would be quite ugly. (I'd have to write a script just to generate my eval command.) Then I'd probably run into some eval expression character limit... I found a 4.1-based workaround using regex-based replace() and relative_time(), which you can see here (if your interested): http://answers.splunk.com/questions/4528/finding-your-local-timezone-with-eval

0 Karma

Lowell
Super Champion

Nope. It has to be within a single eval expression. Since my macro is eval-based, I can't even do any kind of nested macro tricks.

0 Karma

ftk
Motivator

Is there any way you can smuggle a convert num(a) in front of this for your macro?

0 Karma
Get Updates on the Splunk Community!

Welcome to the Splunk Community!

(view in My Videos) We're so glad you're here! The Splunk Community is place to connect, learn, give back, and ...

Tech Talk | Elevating Digital Service Excellence: The Synergy of Splunk RUM & APM

Elevating Digital Service Excellence: The Synergy of Real User Monitoring and Application Performance ...

Adoption of RUM and APM at Splunk

    Unleash the power of Splunk Observability   Watch Now In this can't miss Tech Talk! The Splunk Growth ...