Использование sed для преобразования json

#linux #bash #sed

#linux #bash #sed

Вопрос:

Я пытаюсь использовать sed для преобразования этого json:

 {
  "terraform_version": "0.14.8",
  "terraform_revision": "",
  "provider_selections": {
    "registry.terraform.io/hashicorp/azuread": "1.3.0",
    "registry.terraform.io/hashicorp/azurerm": "2.47.0",
    "registry.terraform.io/hashicorp/cloudinit": "2.1.0",
    "registry.terraform.io/hashicorp/external": "2.0.0",
    "registry.terraform.io/hashicorp/kubernetes": "2.0.2",
    "registry.terraform.io/hashicorp/local": "2.0.0",
    "registry.terraform.io/hashicorp/null": "3.0.0",
    "registry.terraform.io/hashicorp/template": "2.2.0",
    "registry.terraform.io/hashicorp/tls": "3.0.0"
  },
  "terraform_outdated": false
}
 

чтобы выглядеть так:

 {
  "terraform_version": "0.14.8",
  "terraform_revision": "",
  "provider_selections": "{"registry.terraform.io/hashicorp/azuread":"1.3.0","registry.terraform.io/hashicorp/azurerm":"2.47.0","registry.terraform.io/hashicorp/cloudinit":"2.1.0","registry.terraform.io/hashicorp/external":"2.0.0","registry.terraform.io/hashicorp/kubernetes":"2.0.2","registry.terraform.io/hashicorp/local":"2.0.0","registry.terraform.io/hashicorp/null":"3.0.0","registry.terraform.io/hashicorp/template":"2.2.0","registry.terraform.io/hashicorp/tls":"3.0.0"}",
  "terraform_outdated": "false"
}
 

По сути, provider_selections должен быть заключен в кавычки, а кавычки внутри него экранированы. Мне также нужно, чтобы значение terraform_outdated было строкой.

Я попытался это:

 cat jsondata.json | sed 's/{/"{/2' | sed 's/}/"}/1'
 

но я не могу понять остальное.

Комментарии:

1. Используйте инструмент, предназначенный для этой работы, например jq .

2. jq не работает с бегунами github, поэтому я пытаюсь найти обходной путь. Я сообщил о проблеме: github.com/stedolan/jq/issues/2287

3. Чтение вашего билета, связанного выше: это не ошибка jq; Это происходит от чего-то другого. (Это трассировка стека JavaScript, но jq написан не на JavaScript).

4. Что касается этого билета: terraform version -json | tee >(cat >amp;2) | (jq . || cat >/dev/null) кстати, это может дать нам больше возможностей для дальнейшего выяснения, в чем дело. Но в целом, я был бы намного счастливее, пытаясь отладить «почему jq не работает в моей среде github runner?» чем «как я могу редактировать JSON с помощью sed?». Последнее — это то, чего просто не следует делать.

Ответ №1:

Если вы можете использовать python :

 #!/usr/bin/env bash
  
python -c "import json,sys
data=json.loads(open(sys.argv[1]).read())
data['provider_selections'] = json.dumps(data['provider_selections'])
print(json.dumps(data))
" data.json
 

Ответ №2:

Используя sed, это выглядит следующим образом:

 sed -r '/: {/{x;N;:L;N;s/},/},/;TL;s/"/\"/g;x;G;s/n *//g};s/: ([^"].*[^,])(,)?$/: "1"2/' file.json
 

Расширено до нескольких строк

 sed -r '
/: {/{
  x
  N
  :L
    N
    s/},/},/
  TL
  s/"/\"/g
  x
  G
  s/n *//g
}
s/: ([^"].*[^,])(,)?$/: "1"2/
' file.json
 

Однако использование sed для преобразования формата, подобного описанному выше, не является универсальным…

Ответ №3:

Если ed это приемлемо / доступно.

 #!/usr/bin/env bash

ed -s file.json <<-'EOF'
  g/: {/ 1;/},/-1s/"/\"/g
  g/: {/ 1;/},/-1s/[[:blank:]]*//
  g/: {/ 1;/},/s/[[:blank:]]{1,}//
  g/: {/;/},/j
  ., s/(.*) ({?.*}?)/1 "2"/
  ,p
  Q
EOF
 

Если вывод правильный, просто измените Q w , чтобы отредактировать файл на месте.

Тестировалось только на GNU ed .