JQ在将它添加到第二个位置时从我的整数中减去13,但不是第一个

时间:2018-05-24 20:09:47

标签: json bash precision jq

我有一个脚本,它使用Docker env vars在启动时配置json文件。该函数在相同的JQ命令中使用相同的ENV var两次,并且在第一个位置,整数保持为set,在第二行中,JQ从数字中减去13(WTF?)。有谁能解释一下?更重要的是,我如何防止这种情况发生。

注意:为了使配置有效,第二个实例必须是不带引号的整数。测试显示引用整数会导致预期输出,但配置无效。

Env Var

DISCORD_CHANNEL=448887356515418113

Bash功能:

function updateDiscordConfig {
  echo "Setting Discord configuration..."
  jq ".discord |= . + {\"token\":\"${DISCORD_TOKEN}\"} | .discord.channels.channels |= . + {\"${DISCORD_CHANNEL}\": {}} | .minecraft.dimensions.generic |= . + {\"discordChannel\": [${DISCORD_CHANNEL}]}" ${DISCORD_SRCCONFIG} | sponge ${DISCORD_DESTCONFIG}
}

输出:

// First output
"channels": {
  "448887356515418113": {}
}

// Second output
"discordChannel": [
    448887356515418100
],

更新:我已使用sed替换了第二个实例更新:

function updateDiscordConfig {
  echo "Setting Discord configuration..."
  jq ".discord |= . + {\"token\":\"${DISCORD_TOKEN}\"} | .discord.channels.channels |= . + {\"${DISCORD_CHANNEL}\": {}}" ${DISCORD_SRCCONFIG} | sponge ${DISCORD_DESTCONFIG}
  sed -i "/discordChannel/c\   \"discordChannel\" : [${DISCORD_CHANNEL}]," ${DISCORD_DESTCONFIG}
}

2 个答案:

答案 0 :(得分:2)

不幸的是,你遇到了jq的一个主要限制 - 数值精度。 jq将JSON数字映射到IEEE 754 64位数字。这将在jq FAQ"注意事项"

中讨论

变通方法

如果您不想使用其他编程语言, 你可以使用" BigInt" jq的模块 - https://gist.github.com/pkoppstein/d06a123f30c033195841

但是,这适用于字符串表示,因此它可能比您的用例更有麻烦。

如果您只需要添加,可以使用此jq def:

# The args should be strings representing non-negative integers
# without a leading "+":
def add(num1;num2):
  if (num1|length) < (num2|length) then add(num2;num1)
  else  (num1 | explode | map(.-48) | reverse) as $a1
      | (num2 | explode | map(.-48) | reverse) as $a2
      | reduce range(0; num1|length) as $ix
          ($a2;  # result
           ( $a1[$ix] + .[$ix] ) as $r
           | if $r > 9 # carrying
             then
               .[$ix + 1] = ($r / 10 | floor) + 
                            (if $ix + 1 >= length then 0 else .[$ix + 1] end )
               | .[$ix] = $r - ( $r / 10 | floor ) * 10
             else
               .[$ix] = $r
             end )
      | reverse | map(.+48) | implode
  end ;

用法

使用它的一种方法是将它复制到jq库中的文件(比如add.jq)(例如〜/ .jq /) 并使用include包含它,例如如下所示:

jq -n  'include "add"; 
        add("448887356515418113";"448887356515418113")'
"897774713030836226"

答案 1 :(得分:2)

通常,出于这个原因,您不应该在JSON中对大型数字字符串使用数字类型。但是,如果Discord需要一个整数 - 如果它能够从配置中获取正确的非基础值,而用于解析它 - 那么你需要另一种方法。也许Python?

function updateDiscordConfig {
  echo "Setting Discord configuration..."
  python -c "import json, sys; conf = json.load(sys.stdin); conf['discord']['token']='$DISCORD_TOKEN'; conf['discord']['channels']['channels']='$DISCORD_CHANNEL';conf['minecraft']['dimensions']['generic']['discordChannel']=[$DISCORD_CHANNEL];print(json.dumps(conf));" ${DISCORD_SRCCONFIG} | sponge ${DISCORD_DESTCONFIG}
}