Search code examples
jsoncommand-line-argumentsjqstring-interpolation

jq --arg variable used in quoted string within select()


I want to select() an object based on a string containing a jq variable ($ARCH) using -arg jq argument. Here's the use-case while looking for "/bin/linux/$ARCH/kubeadm" from Google...

# You may need to install `xml2json` IE 
# sudo gem install --no-rdoc --no-ri xml2json and run the script I wrote to do the xml2json:

#!/usr/bin/ruby
# Written by Jim Conner
require 'xml2json'

xml = ARGV[0]

begin
  if xml == '-'
    xdata = ARGF.read.chomp
    puts XML2JSON.parse(xdata)
  else
    puts XML2JSON.parse(File.read(file2parse).chomp)
  end
rescue => e
  $stderr.puts 'Unable to comply: %s' % [e.message]
end

Then run the following:

curl -sSL https://storage.googleapis.com/kubernetes-release/ > /var/tmp/k8s.xml | \
xml2json - | \
jq --arg ARCH amd64 '[.ListBucketResult.Contents[] | select(.Key | contains("/bin/linux/$arch/kubeadm"))]'

...which returns an empty set because jq doesn't transliterate inside quotes. I know I can get around this by using multiple select/contains() but I'd prefer not to if possible.

jq simply may not do it, but if someone knows a way to do it, I'd much appreciate it.


Solution

  • jq does support string interpolation, and in your case the string would be:

    "/bin/linux/\($ARCH)/kubeadm"
    

    Notice that this is not a JSON string: the occurrence of "\(" signals that the string is subject to interpolation. Very nifty.

    (Alternatively, you could of course use string concatenation: "/bin/linux/" + $ARCH + "/kubeadm")

    Btw, you might wish to avoid contains here. Its semantics is (are?) quite complex and perhaps counter-intuitive. Consider using startswith, index, or (for regex matches) test.