Search code examples
yq

YQ update style of key/value attribute


On YQ v4, i would need to transform a yaml file like:

test:
  A: "customData"
  B: 123

Into a .env format :

A="customData"
B=123

I have come up with this command:

yq '.test | to_entries | .[] | .key + "=" + .value"' ./input.yaml > ./.env

Unfortunatly, quotes disapear in the output with this command. Earlier YQ version had a tostring built-in function, but not it is not working anymore apparently wit v4. I have tried style="double" without any success so far.

Any idea?

Thank you in advance for your help.


Solution

  • Earlier YQ version had a tostring built-in function, but not it is not working anymore apparently wit v4.

    You seem to be confusing mikefarah/yq with kislyuk/yq. While the former (currently on version 4.40.5) is heavily inspired by jq but has its own DSL that never included tostring, the latter (currently on version 3.2.2) actually uses jq under the hood which of course did and still does have tostring.

    Yet, neither jq's tostring (available in kislyuk's yq), nor styling with style="double" or converting with tag="!!str" (both available in mikefarah's yq) would automatically wrap strings into double quotes. Note that quotes could easily be added using … + "\"" + … (yet, selectively applying that to only strings would be quite different for the two implementations), but in the end you most probably want more than just quotes around strings anyway, as you likely want to properly encode the value part (for instance, you probably want to somehow escape quotes that were already part of the data).

    And that proper encoding is the key to your solution. You could, for example, use the tojson or @json encoders (supported by kislyuk/yq since the beginning (as its introduction into jq predates kislyuk/yq), and by mikefarah/yq since version 4.14.1 as tojson and since version 4.16.1 as @json), which both provide you with double quotes on strings while leaving numbers as is.

    # works with all versions of kislyuk/yq, and with mikefarah/yq 4.16.1+
    .test | to_entries | .[] | .key + "=" + (.value | @json)
    
    # works with all versions of kislyuk/yq, and with mikefarah/yq 4.14.1+
    # but note that with mikefarah/yq, additional empty lines are added
    .test | to_entries | .[] | .key + "=" + (.value | tojson)
    
    A="customData"
    B=123
    

    Note, however, that it is not obvious from your sample how you want other (esp. edge-)cases to be handled, and whether all the aspects of this JSON-encoding (e.g. escaping double quotes in strings with backslash, removing insignificant whitespace from the formatting of arrays and objects, etc.) actually do fit your use-case. In fact, as you are writing the output into a file called .env, I'd guess that you want the output to be subsequently interpreted by a shell. For POSIX shells, you could, for example, use the @sh encoder instead (supported by kislyuk/yq since the beginning (as its introduction into jq predates kislyuk/yq), and by mikefarah/yq since version 4.31.1). This way, you are guaranteed to get a valid encoding that can always be interpreted by the shell, but both implementations prefer using single quotes over double quotes for strings (making the encoding less noisy on special characters like $ as they don't require escaping).

    # works with kislyuk/yq
    .test | to_entries | .[] | .key + "=" + (.value | @sh)
    
    A='customData'
    B=123
    

    The mikefarah/yq implementation even limits the quoting to where the shell requires their presence, which eventually might (and does indeed in this case) lead to the complete omission of quotes. Also, as the @sh encoder of this implementation only processes strings, a conversion to !!str using tag or type becomes necessary.

    # works with mikefarah/yq 4.31.1+, but needs conversion to !!str first
    .test | to_entries | .[] | .key + "=" + (.value | . type = "!!str" | @sh)
    
    A=customData
    B=123
    

    But even with this shell-oriented encoding, you'd still need to determine whether it fits your use-case for data types other than those shown in your sample (e.g. kislyuk/yq would convert arrays into space-separated strings but refuse the conversion of objects altogether, while mikefarah/yq would simply produce the empty string when the iterable types !!seq and !!map are being converted into !!str).