Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dot want to point at document root node absolutely #1759

Open
wangrongjun opened this issue Aug 20, 2023 · 2 comments
Open

dot want to point at document root node absolutely #1759

wangrongjun opened this issue Aug 20, 2023 · 2 comments

Comments

@wangrongjun
Copy link

I have a yaml as below, and I want to do a pre-handle, replace ${xxx} to actual value, which from yaml itself.

es-host: 192.168.1.101
gerrit-host: 192.168.1.102
deploy-info:
  es:
    server: ${es-host}:9200
  gerrit:
    server: ${gerrit-host}:8080

So, I replace by sub and eval:

yq -i '(.. | select(tag=="!!str")) |= (. | sub("\$\{(.+?)\}", eval(".$1")))' test.yaml

I expected:

es-host: 192.168.1.101
gerrit-host: 192.168.1.102
deploy-info:
  es:
    server: 192.168.1.101:9200
  gerrit:
    server: 192.168.1.102:8080

But actually is:

es-host: 192.168.1.101
gerrit-host: 192.168.1.102
deploy-info:
  es:
    server: :9200
  gerrit:
    server: :8080

You see, the eval can't get expected value, it just null. Because dot point at current node position after select, no longer point at document root position, and .deploy-info.es.server.es-host not exist, so eval return null.

Is there any way or a sign, can point at document root node absolutely?
Such as !, if I use eval("!.es-host"), it will find by document root absolutely, not relatively.
Thanks.

@mikefarah
Copy link
Owner

mikefarah commented Sep 4, 2023

This was more complicated than I though. The short answer to your question is that you can use a create a variable to reference the root . as $r - however this by itself it not enough - because the sub command can only take a string to substitute to, not an expression. In the end I used 'capture' to grab the variable name like so:

yq '. as $r | "\$\{(?P<x>.+?)\}(?P<b>.*)" as $reg | 
with(.. | select(tag=="!!str" and match($reg)) ; 
capture($reg) as $c | . = ($r | eval("." + $c.x) + $b))

Explanation:

  • . as $r will capture the root into the $r variable
  • Because I need to use the reg ex twice, I saved that into a $reg variable as well
  • "\$\{(?P<x>.+?)\}(?P<b>.*)" will capture the variable into 'x' and the rest of the string into 'b'
  • with(.. | select(tag=="!!str" and match($reg)) ; will loop over all the strings that match that regex in the document
  • capture($reg) as $c will run the reg ex with the capture groups, and put the result into the variable c
  • Finally . = ($r | eval("." + $c.x) + $b will update the current string . by running the variable x from the capture group against the root $r | eval("." + $c.x) and the appending the remaining original string b.
  • Phew.

Edit: formatting, and link to docs: https://mikefarah.gitbook.io/yq/operators/string-operators#capture-named-groups-into-a-map

@jmdesprez
Copy link

Hello,
Thanks for the answer.
I spotted a small typo, $b should be $c.b 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants