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

これにより、1回の呼び出しで2つの操作が正しく結合されますjq

このコマンドは、jq以前に作成したシェル変数から取得した値を使用して、3つの内部文字列変数をインスタンス化します。--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 "==============================================================================================================="
´´´

関連情報