jq:スペースで区切られた文字列を値として渡す

jq:スペースで区切られた文字列を値として渡す

キーと値の両方が変数として転送される既存のJSONファイルに新しいキーペアを作成しようとしています。私には次のコマンドラインがあります。

jq --arg key "$key" --arg value "$value" 'getpath(path('$key')) = '$value'' "$json"

場所: $key - キー $value - 値 $json - JSON データを含むファイル

たとえば、私の値はなので、Linux CentOSコマンドを実行すると

+ jq --arg key .operating_system.NAME --arg value 'CentOS Linux' 'getpath(path(.operating_system.NAME)) = CentOS' Linux ./servername_1648782569.json
jq: error: CentOS/0 is not defined at <top-level>, line 1:
getpath(path(.operating_system.NAME)) = CentOS
jq: 1 compile error

UPD:スクリプトが直面しているときの私のJSONデータ:

{
  "operating_system": {}
}

貼り付ける値 NAME="CentOS Linux" のソースは次のとおりです。 /etc/os-release

割り当て機能:

function assign_value ()                                                                          
{                                                                                                 
  if [ -z "$1" ]                                                                                  
  then                                                                                            
    echo __msg_error "Key is not passed as argument."                                             
    exit 1                                                                                        
  elif [ -z "$2" ]                                                                                
  then                                                                                            
    echo __msg_error "Value is not passed as argument."                                           
    exit 1                                                                                        
  elif [ -z "$3" ]                                                                                
  then                                                                                            
    echo __msg_error "JSON file path is not passed as argument."                                  
    exit 1                                                                                        
  fi                                                                                              
                                                                                                  
  key="$1"                                                                                        
  value="$2"                                                                                      
  json="$3"                                                                                       
                                                                                                  
  tmp=$(mktemp)                                                                                   
  jq --arg key "$key" --arg value "$value" "getpath(path("$key")) = "$value"" "$json" > "$tmp"
  mv -- "$tmp" "$json"                                                                            
}                                                                                                 

パラメータが上記の関数に渡される位置

...
if test -e /etc/os-release                                              
then                                                                    
        os_release_path='/etc/os-release'                               
else                                                                    
        os_release_path='/usr/lib/os-release'                           
fi                                                                      
. "${os_release_path}"                                                  
                                                                        
MAJOR_VERSION_ID=$(echo $VERSION_ID | awk -F '.' '{print $1}')          
                                                                        
initialize_new_area "$JSON_AREA" "$JSON"                                
                                                                        
#assign_value "${JSON_AREA}.NAME" "$NAME" "$JSON"                       
assign_value "${JSON_AREA}.ID" "$ID" "$JSON"                            
assign_value "${JSON_AREA}.ID_LIKE" "$ID_LIKE" "$JSON"                  
assign_value "${JSON_AREA}.MAJOR_VERSION_ID" "$MAJOR_VERSION_ID" "$JSON"
...

ベストアンサー1

jqcreatevariablesを使用していますが、式では使用--argしません。jq代わりに二重引用符を使用するため、シェル変数を式に挿入します。これは問題の一部です。

jq文字列または有効なJSON文書以外のものとしてデータを渡すことはできません。表現する(このようなパスは.operating_system.NAME)不可能です。代わりに、文字列が渡され、パス文で解析されます。

jq一重引用符式に変数を使用し、指定された「キー」値を点に分割して、パス式としてjq使用できる値に解析します。jq

jq --arg key "$key" --arg value "$value" '
    setpath($key | split("."); $value)' "$json" > "$tmp"

上記の一重引用符は、シェル変数による$keyシェル拡張を防ぎます。$value代わりに内部変数として扱われjq(正しいエンコーディング)を使用して割り当てられた値を持ちます。--argjq

テスト:

$ cat file
{
  "operating_system": {}
}
$ key="operating_system.release.date"
$ value="2022-04-01"
$ jq --arg key "$key" --arg value "$value" 'setpath($key|split(".");$value)' file
{
  "operating_system": {
    "release": {
      "date": "2022-04-01"
    }
  }
}

この特定の方法で配列要素の設定をサポートするには、パス要素を数値に変換する必要がありますが、変換に失敗した場合は、その要素を文字列として使用するように戻す必要があります。

jq --arg key "$key" --arg value "$value" '
    setpath($key | split(".") |
        map(try tonumber catch null // .); $value)' file

テスト:

$ key="operating_system.dates.0"
$ value="2022-04-02"
$ jq --arg key "$key" --arg value "$value" 'setpath($key|split(".")|map(try tonumber catch null // .); $value)' file
{
  "operating_system": {
    "dates": [
      "2022-04-02"
    ]
  }
}

おすすめ記事