shell Bash:忽略使用jq解析失败的JSON中的键值对

mqkwyuun  于 2023-02-05  发布在  Shell
关注(0)|答案(4)|浏览(227)

我正在编写一个bash脚本来读取JSON文件并将键值对导出为环境变量,虽然我可以提取键值对,但我很难跳过那些无法被jq解析的条目。
JSON(key3应无法解析)

{
 "KEY1":"ABC",
 "KEY2":"XYZ",
 "KEY3":"---ABC---\n
dskfjlksfj"

}

以下是我尝试的方法

for pair in $(cat test.json  | jq -r -R  '. as $line | try fromjson catch $line | to_entries | map("\(.key)=\(.value)") | .[]' ); do
    echo $pair
    export $pair
done

这就是错误

jq: error (at <stdin>:1): string ("{") has no keys
jq: error (at <stdin>:2): string ("  \"key1...) has no keys

我的代码是基于这些职位:

  1. How to convert a JSON object to key=value format in jq?
  2. How to ignore broken JSON line in jq?
  3. Ignore Unparseable JSON with jq
e5nqia27

e5nqia271#

下面是对修改后的问题的回答,不幸的是,它只在某些有限的情况下有用,不包括你给予的例子(基本上,它取决于jq的解析器能够在文件结束前恢复)。

while read -r line ; do 
    echo export "$line"
done < <(< test.json jq -rn '
  def do:
    try inputs catch null
    | objects
    | to_entries[]
    | "\(.key)=\"\(.value|@sh)\"" ;
  recurse(do) | select(.)
')

请注意,可能需要进一步的改进,特别是当用作shell变量名的键名可能有些可疑的时候。

5t7ly7z5

5t7ly7z52#

[Note:这个回答是针对最初的问题,后来有所改变。这个回答基本上假设输入由JSONLines和其他线路组成。)
由于目标似乎是忽略没有有效键值对的行,因此可以简单地使用catch empty

while read -r line ; do 
    echo export "$line"
done < <(test.json jq -r -R  '
  try fromjson catch empty
  | objects
  | to_entries[]
  | "\(.key)=\"\(.value|@sh)\"" 
')

还要注意@sh和shell的read的使用,以及.value(在jq中)和$line(在shell中)都被引用的事实,这些对于健壮性来说都很重要,尽管为了提高健壮性可能还需要进一步的改进。

lyr7nygr

lyr7nygr3#

也许有一种算法可以修复上游系统产生的破损JSON,如果没有,下面是一个可怕但可能有用的“黑客”,它至少可以捕获Q中示例中的KEY1和KEY2:

jq -Rr '
   capture("\"(?<key>[^\"]*)\"[ \t]*:[ \t]*(?<value>[^}]+)") 
   | (.value |= sub("[ \t]+$"; "") )  # trailing whitespace
   | if .value|test("^\".*\"") then .value |= sub("\"[ \t]*[,}[ \t]*$"; "\"") else . end
   | select(.value | test("^\".*\"$") or (contains("\"")|not) )  # a string or not a string
   | "\(.key)=\(.value|@sh)" 
'
46qrfjad

46qrfjad4#

示例中损坏的JSON可以通过多种方式修复,例如:

sed '/\\n$/{N; s/\\n\n/\\n/;}'

产生:

{
 "KEY1":"ABC",
 "KEY2":"XYZ",
 "KEY3":"---ABC---\ndskfjlksfj"

}

至少这是JSON:-)

相关问题