【问题标题】:Iterate over an array of objects and format the string遍历对象数组并格式化字符串
【发布时间】:2021-03-29 13:16:32
【问题描述】:

我有一个这样的 json 文件:

[
  {
    "classname": "Test endpoint",
    "name": "expect failure",
    "failure_system_out": "expected 404 Not Found\nError in test endpoint\n\tat Test._assertStatus"
  },
  {
    "classname": "Test inner functions",
    "name": "expect failure",
    "failure_system_out": "Example fo test\n\tExpect 4 and got 5"
  }
]

如您所见,“failure_system_out”中的值是一个包含换行符 (\n) 和制表符 (\t) 的字符串。

我正在尝试读取文件,循环对象并使用以下代码打印它们:

jq -c '.[]' myfile.json | while read i; do
    test_name=$(echo "$i" | jq -r .name)
    system_error=$(echo "$i" | jq -r .failure_system_out)
    printf "${system_error}"

done

问题在于,使用这种方法,printf 不会根据新行和制表符打印脚本,而是打印类似 expected 404 Not FoundnError in test endpointntat Test._assertStatus 的内容 基本上,我认为 jq -c 删除了 \ 字符,因此 printf 不能正常工作。

如何遍历存储在文件中的对象数组并保留用于格式化字符串的字符?

第一项的期望输出:

expected 404 Not Found
Error in test endpoint
   at Test._assertStatus

第二个项目的期望输出:

Example fo test
    Expect 4 and got 5

【问题讨论】:

  • 请添加所需的输出!
  • jq 设法看到扩展变量之前,内置的read 命令删除了\`
  • 因为没有使用-r 标志。例如read -r
  • @Jetchisel 你能写出适用于这个例子的代码吗?
  • Desired output:Example fo test...怎么了?

标签: bash jq


【解决方案1】:

只需使用jq,它本身就是一种脚本语言。

$ jq -r '.[0].failure_system_out' /tmp/1
expected 404 Not Found
Error in test endpoint
    at Test._assertStatus
$ jq -r '.[1].failure_system_out' /tmp/1
Example fo test
    Expect 4 and got 5
$ jq -r '.[] | .name as $test_name | .failure_system_out as $system_error | $system_error' /tmp/1
expected 404 Not Found
Error in test endpoint
    at Test._assertStatus
Example fo test
    Expect 4 and got 5

至于使用 bash,请先阅读 https://mywiki.wooledge.org/BashFAQ/001 。我喜欢使用base64 将上下文从jq 正确传输到bash 并处理所有极端情况。

jq -r '.[] | @base64' /tmp/1 |
while IFS= read -r line; do
    line=$(<<<"$line" base64 -d);
    test_name=$(<<<"$line" jq -r .name);
    system_error=$(<<<"$line" jq -r .failure_system_out);
    printf "%s\n" "$system_error";
done

但这里不需要,只需一个适当的while read 循环就足够了:

jq -c '.[]' /tmp/1 |
while IFS= read -r line; do
    test_name=$(<<<"$line" jq -r .name);
    system_error=$(<<<"$line" jq -r .failure_system_out);
    printf "%s\n" "$system_error";
done

【讨论】:

  • 感谢您的解释!
【解决方案2】:

@KamilCuk's answer 效果很好,并且提供了更多的控制权。

我想我仍然会分享这个 唯一的解决方案:

printf "%s\n" "$(jq -r -c '.[] | .failure_system_out' test.json)"

这将产生:

expected 404 Not Found
Error in test endpoint
    at Test._assertStatus
Example fo test
    Expect 4 and got 5

【讨论】:

    【解决方案3】:

    这个问题似乎交织在几个目标中,但无论如何:

    • 没有必要多次调用 jq,并且

    • 应该没有必要使用 base64 转换,除非与感兴趣的键对应的值包含 NUL。

    如果目标只是发出.failure_system_out 的值,那么:

     jq -r '.[].failure_system_out' test.json
    

    会做的。

    如果.name.failure_system_out 的值必须作为bash 变量单独提供,那么考虑:

    while IFS= read -d $'\0' system_error ; do
        IFS= read -d $'\0' test_name
        printf "%s\n" name="$test_name"
        printf "%s\n" fso="$system_error"
        echo ""
    done < <(jq -rj '.[] | [.name, .failure_system_out, ""] | join("\u0000")' test.json)
    

    readarray 也可以使用——参见例如 Storing JQ NULL-delimited output in bash array

    【讨论】:

      猜你喜欢
      • 2020-01-12
      • 1970-01-01
      • 2018-07-06
      • 1970-01-01
      • 1970-01-01
      • 2021-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多