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"
    ]
  }
}

관련 정보