So we’re going to go down a little rabbit hole regarding groovy string interpolation which I found odd enough to want to write up.
First, some basics. Groovy uses string interpolation syntax similar to bash, which looks like this:
String foo = 'I am a fancy string'
println("My string: ${foo}")
Pretty straightforward, with a few interesting bits. First, you may have noted that we used both single and double quotes. Single quotes give you a string literal (think Python r-strings) whereas double quotes will give you the interpolated output (think Python f-strings).
Quick aside, technically the interpolated output you get is a GString type, which:
- Can lead to very humorous discussions with team mates (and MUCH MORE HILARIOUS conversations to those within earshot and no context)
- Can lead to some odd behavior when checking whether an interpolated string is in a collection
Just assume GStrings are going to make your life harder than it otherwise would be. We won’t go into it because that’s now what we’re here to talk about today.
The problem
So now let’s say we’ve got some environment variable that’s name is, well, variable. Perhaps this variable is dependent on system, architecture, whatever. The point is we want to be able to access the correct one.
So, to access an environment variable (using a Jenkins environment as an example) is simply:
env.ENVAR_NAME
You can put it in a string using interpolation like so:
String myEnvar = "${env.ENVAR_NAME}"
Now let’s assume we want to access a home directory which is unique on each platform. We can do it a couple of ways:
String myHome = ''
if (platform == 'WINDOWS') {
myHome = "${env.WINDOWS_HOME}"
} else if (platform == 'LINUX') {
myHome = "${env.LINUX_HOME}"
} ...
We could also us a switch statement, index into a map, whatever. All of these work and are fine, but it’s a lot of boilerplate code. If only there was a way we could use nested interpolation.
Which we can!
The solution
While this may look weird, it does in fact work:
Map foo = [foo:1, bar:2]
baz = 'bar'
println("Bar value: ${foo."${baz}"}")
I’m using baz here to refer to ‘bar’ to ensure it’s not just using the characters of the variable name. I know it’s a bit confusing and I’m sorry.
In fact, you can test it yourself (I like tutorialspoint’s groovy web runtime):

Now, at first glance this code looks wrong, but as you can see it does run as expected. This ends up behaving similar to nested f-strings, even if the syntax is a bit wonkier. Going back to our home example, we’d end up with code like this:
String myHome = "${env."${platform}"_HOME}"
I’ll admit it looks a bit odd, but ultimately it’s pretty easy to read and gives you the expected output.
So nothing too crazy, but perhaps slightly counterintuitive to use the expansion outside of double quotes. The place it gets weird is if you try to treat it like a string itself.
Other (failed) approaches
At first pass, you might say “oh all it’s doing is concatenating by putting strings next to each other. You can replicate it using string concatenation.”

You would be wrong.
“Okay but maybe we just need to remove the expansion indicators around baz?”

Nope.
“We probably don’t even need to close the quotes first and can use it like Python’s nested f-string.”

Also no.
“Maybe…”

No again.
“Well perhaps StringBuilder…”

Negatory.
So, as shown there’s really only one way to make it work and it’s pretty picky about how it does so it’s good to know the exact incantation.
As for why this specific approach works, I can’t find the exact documentation that describes this behavior, though there are a few examples here and there on places like stack overflow. All in all it’s an interesting rabbit hole to have followed and is nice to have in the back pocket.