bash를 사용하여 콘텐츠를 구문 분석하고 json에 추가하는 방법은 무엇입니까?

bash를 사용하여 콘텐츠를 구문 분석하고 json에 추가하는 방법은 무엇입니까?

나는 다음 Stackexchange 기사의 아이디어를 따랐습니다.

그런데 선택하고 추가할 때 따옴표에 문제가 있습니다.

내 샘플 json 파일은 다음과 같습니다.

{
  "options": [
    {
      "label": "22",
      "value": "2022"
    },
    {
      "label": "23",
      "value": "2023"
    }
  ]
}

이것은 내 테스트 bash 스크립트입니다.

#!/bin/bash

previous_year=$(date --date="$(date +'%Y') - 1 year" +%Y)
last_year=$((previous_year + 31))
label=$((last_year -2000))

echo ${last_year}

jq 'del(.options[]? | select(.label == \"${previous_year}\"))' temp.json
jq '.options += [{
      "label": '${label}',
      "value": '${last_year}'
    }]' temp.json

이 샘플 파일을 사용하여 bash 스크립트를 실행하면 jq: error: Syntax error, Unexpected INVALID_CHARACTER (Unix shell quoteing issue?) at , line 1: del(.options[]? | select(.label == "$)이 발생합니다. { 이전_연도}"))
jq: 1 컴파일 오류

"를 제거하면 실행되지만 따옴표가 없는 것처럼 보이므로 제거할 항목을 찾을 수 없습니다. 또한 요소를 배열에 추가하지만 따옴표는 추가하지 않습니다.

어떻게 해야 합니까?

  • 따옴표가 있는 요소 찾기
  • 인용된 요소 추가

예상 결과(내가 달성하고 싶은 것)는 다음과 같습니다.

{
  "options": [
    {
      "label": "23",
      "value": "2023"
    },
    {
      "label": "53",
      "value": "2053"
    }
  ]
}

답변1

label셸 변수에 올바른 값이 있고 해당 값을 가진 배열의 모든 항목을 삭제 last_year하고 해당 값과 값을 가진 새 항목을 추가한다고 가정합니다 .previous_yearoptionsvalue$previous_yearlabel$labelvalue$last_year

jq  --arg add_label "$label" \
    --arg add_value "$last_year" \
    --arg del_value "$previous_year" '
    del(.options[]? | select(.value == $del_value)) |
    .options += [{ label: $add_label, value: $add_value }]' file

이는 한 번의 호출로 두 가지 작업을 올바르게 결합합니다 jq.

이 명령은 jq이전에 생성한 셸 변수에서 얻은 값을 사용하여 세 개의 내부 문자열 변수를 인스턴스화합니다. --arg셸 변수에서 생성된 내부 문자열 변수를 사용하면 값이 올바르게 인코딩되도록 보장됩니다(이렇게 하면 코드 삽입 취약점을 방지할 수 있습니다).

귀하의 코드에서와 마찬가지로 배열이 존재하지 않는 경우 오류를 .options[]?피하기 위해 대신 사용합니다 . 존재하는 경우 값이 (쉘 변수의 값을 갖는 내부 변수)인 항목은 제거됩니다 . select를 사용해 보셨지만 오타일 수도 있다고 생각합니다..options[]optionsvalue$del_valueprevious_yearlabel

(아마도) 수정된 문서는 다음 단계로 전달되어 배열에 새 요소가 추가됩니다 options. 배열이 이전에 존재하지 않은 경우 단일 요소로 생성됩니다.

또한 jq내부 편집을 수행하지 않으므로 위 명령의 출력을 새 이름으로 리디렉션한 다음 원본 파일을 해당 새 파일로 바꿔야 함을 의미합니다. 또는 GNU를 사용하십시오 sponge.

jq ...as above... file | sponge file

(파일 이름은 이라고 가정합니다 file.)

답변2

#!/bin/bash
file=temp.json
now="$(date)"
previous_year=$(date --date="$(date +'%Y') - 1 year" +%Y)
last_year=$((previous_year + 31))
label=$((last_year -2000))
echo "==============================================================================================================="
echo "| Started parsing json file at script at: $file"
echo "| Started at:                             $now"
echo "| previous year is:                       $previous_year"
echo "| last year to be at json array is:       $last_year"
echo "| label assigned to the last year :       $label"
echo "==============================================================================================================="

if cat $file | grep $previous_year
then
  jq --arg key "$previous_year" 'del(.options[] | select(.value == $key))' $file >> new.json
  jq --arg key "$label" --arg val "$last_year" '.options += [{
        "label": $key,
        "value": $val
      }]' new.json >> new2.json
  mv new2.json $file
  rm new.json
  echo "last year found and parsed"  
else
  echo "nothing to be done"
fi

now="$(date)"
echo "==============================================================================================================="
echo "| Ended script at: $now"
echo "==============================================================================================================="
´´´

관련 정보