如何使用jq在字符串中漂亮地打印JSON?

如何使用jq在字符串中漂亮地打印JSON?,json,jq,pretty-print,Json,Jq,Pretty Print,我正在用jq编写一个更复杂的转换,我想做的一件事是在字符串中有一个漂亮的打印JSON。例如: echo '{"foo": "bar"}' | jq '{json: {other: .} | tostring}' 给予 虽然我想得到: { "json": "{\n \"other\": {\n \"foo\": \"bar\"\n }\n}" } 我也尝试过tojson和@json,但它们给出的结果与tostring相同。有可能用jq吗?或者我必须求助于其他的诡计吗?请注意,我需

我正在用jq编写一个更复杂的转换,我想做的一件事是在字符串中有一个漂亮的打印JSON。例如:

echo '{"foo": "bar"}' | jq '{json: {other: .} | tostring}'
给予

虽然我想得到:

{
  "json": "{\n  \"other\": {\n    \"foo\": \"bar\"\n  }\n}"
}
我也尝试过
tojson
@json
,但它们给出的结果与
tostring
相同。有可能用jq吗?或者我必须求助于其他的诡计吗?请注意,我需要在输出中包含多个带格式JSON的字符串,而不是像示例中那样的字符串。

echo '{"foo": "bar"}' | jq '{other: .}' | jq -Rs '{json: .}'
产生:

{
  "json": "{\n  \"other\": {\n    \"foo\": \"bar\"\n  }\n}\n"
}
删除终止的
“\n”
的一种方法是将其剥离:

echo '{"foo": "bar"}' | jq '{other: .}' | jq -Rs '{json: .[:-1]}'
这:

产生:

{
  "json": "{\n  \"other\": {\n    \"foo\": \"bar\"\n  }\n}\n"
}
删除终止的
“\n”
的一种方法是将其剥离:

echo '{"foo": "bar"}' | jq '{other: .}' | jq -Rs '{json: .[:-1]}'

最后我编写了一个简单的格式化函数:

#   9 = \t
#  10 = \n
#  13 = \r
#  32 = (space)
#  34 = "
#  44 = ,
#  58 = :
#  91 = [
#  92 = \
#  93 = ]
# 123 = {
# 125 = }

def pretty:
  explode | reduce .[] as $char (
    {out: [], indent: [], string: false, escape: false};
    if .string == true then
      .out += [$char]
      | if $char == 34 and .escape == false then .string = false else . end
      | if $char == 92 and .escape == false then .escape = true else .escape = false end
    elif $char == 91 or $char == 123 then
      .indent += [32, 32] | .out += [$char, 10] + .indent
    elif $char == 93 or $char == 125 then
      .indent = .indent[2:] | .out += [10] + .indent + [$char]
    elif $char == 34 then
      .out += [$char] | .string = true
    elif $char == 58 then
      .out += [$char, 32]
    elif $char == 44 then
      .out += [$char, 10] + .indent
    elif $char == 9 or $char == 10 or $char == 13 or $char == 32 then
      .
    else
      .out += [$char]
    end
  ) | .out | implode;
它在空对象和数组中添加了不必要的空行,但对于我来说已经足够好了。例如(单独使用):

函数保存在
pretty.jq
test.json
文件中的位置是:

{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"key":"string with \"quotes\" and \\"},"geometry":{"type":"Polygon","coordinates":[[[24.2578125,55.178867663281984],[22.67578125,50.958426723359935],[28.125,50.62507306341435],[30.322265625000004,53.80065082633023],[24.2578125,55.178867663281984]]]}}]}
给出:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "key": "string with \"quotes\" and \\"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              24.2578125,
              55.178867663281984
            ],
            [
              22.67578125,
              50.958426723359935
            ],
            [
              28.125,
              50.62507306341435
            ],
            [
              30.322265625000004,
              53.80065082633023
            ],
            [
              24.2578125,
              55.178867663281984
            ]
          ]
        ]
      }
    }
  ]
}

最后我编写了一个简单的格式化函数:

#   9 = \t
#  10 = \n
#  13 = \r
#  32 = (space)
#  34 = "
#  44 = ,
#  58 = :
#  91 = [
#  92 = \
#  93 = ]
# 123 = {
# 125 = }

def pretty:
  explode | reduce .[] as $char (
    {out: [], indent: [], string: false, escape: false};
    if .string == true then
      .out += [$char]
      | if $char == 34 and .escape == false then .string = false else . end
      | if $char == 92 and .escape == false then .escape = true else .escape = false end
    elif $char == 91 or $char == 123 then
      .indent += [32, 32] | .out += [$char, 10] + .indent
    elif $char == 93 or $char == 125 then
      .indent = .indent[2:] | .out += [10] + .indent + [$char]
    elif $char == 34 then
      .out += [$char] | .string = true
    elif $char == 58 then
      .out += [$char, 32]
    elif $char == 44 then
      .out += [$char, 10] + .indent
    elif $char == 9 or $char == 10 or $char == 13 or $char == 32 then
      .
    else
      .out += [$char]
    end
  ) | .out | implode;
它在空对象和数组中添加了不必要的空行,但对于我来说已经足够好了。例如(单独使用):

函数保存在
pretty.jq
test.json
文件中的位置是:

{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"key":"string with \"quotes\" and \\"},"geometry":{"type":"Polygon","coordinates":[[[24.2578125,55.178867663281984],[22.67578125,50.958426723359935],[28.125,50.62507306341435],[30.322265625000004,53.80065082633023],[24.2578125,55.178867663281984]]]}}]}
给出:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "key": "string with \"quotes\" and \\"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              24.2578125,
              55.178867663281984
            ],
            [
              22.67578125,
              50.958426723359935
            ],
            [
              28.125,
              50.62507306341435
            ],
            [
              30.322265625000004,
              53.80065082633023
            ],
            [
              24.2578125,
              55.178867663281984
            ]
          ]
        ]
      }
    }
  ]
}

如果我需要有多个这样的格式化字符串呢?假设输入是
[{“foo”:“one”},{“foo”:“two”},…]
,输出是
[{“other”:“…”},{“other”:“…”},…”
。我还需要使用输入JSON的一些属性来创建输出。假设输入是
[{“foo”:“one”,“prop”:“prop one”},{“foo”:“two”,“prop”:“prop two},…”
,输出是
[{“other”:(格式化的{other:{foo:one}),“prop”:“prop one”},{“other”:(格式化的{other:{foo:two}),“prop two},…)
。我认为在jq中编写一个可以漂亮打印JSON字符串的自定义函数可能是最简单的解决方案。如果我需要多个这样的格式化字符串呢?假设输入是
[{“foo”:“one”},{“foo”:“two”},
,输出是
[{“other”:“…”},{“other”:“…},…]
。我还需要使用输入JSON的一些属性来创建输出。假设输入是
[{“foo”:“one”,“prop”:“prop one”},{“foo”:“two”,“prop”:“prop two},…”
,输出是
[{“other”:(格式化的{other:{foo:one}),“prop one”},{“other”:(格式化的{other:{foo:two})”,“prop two:“prop two.”},…]
。我认为在jq中编写一个可以漂亮地打印JSON字符串的自定义函数可能是最简单的解决方案。谢谢,@kszafran。我修改了您的函数,分别打印空数组和空对象的
[]
{}
。谢谢,@kszafran。我修改了您的函数,以打印
[]
{}
分别用于空数组和对象。