Let's say you have two fields like so:
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
evalto 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
I guess I'm looking for counterpart of
tostring. Is there some an undocumented "tonumber()" or similar function?
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.
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
xx, and so forth. And finally, we can invoke
len on the resulting string (
xx maps to
* | 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
a b c ----- ----- - 0001L 0002L 3
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
relative_time(), which you can see here (if your interested): http://answers.splunk.com/questions/4528/finding-your-local-timezone-with-eval
+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?...)
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
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.