sourcetip

파이프 구분 키 및 bash 값에서 jq를 사용하여 JSON 생성

fileupload 2023. 3. 9. 22:16
반응형

파이프 구분 키 및 bash 값에서 jq를 사용하여 JSON 생성

bash 문자열에서 json 개체를 생성하려고 합니다.문자열은 다음과 같습니다.

CONTAINER|CPU%|MEMUSAGE/LIMIT|MEM%|NETI/O|BLOCKI/O|PIDS
nginx_container|0.02%|25.09MiB/15.26GiB|0.16%|0B/0B|22.09MB/4.096kB|0

이 출력은 docker stats 명령어의 출력이며 최종 목표는 사용자 지정 메트릭을 aws cloudwatch에 게시하는 것입니다.이 문자열을 json으로 포맷하고 싶습니다.

{
    "CONTAINER":"nginx_container",
    "CPU%":"0.02%", 
    ....
}

이전에 jq 명령어를 사용한 적이 있는데, 이 경우 잘 될 것 같지만 아직 좋은 해결책이 나오지 않았습니다.변수 이름 하드코딩 및 sed 또는 awk를 사용한 색인화 이외.그런 다음 처음부터 json을 만듭니다.어떤 제안이라도 해주시면 감사하겠습니다.감사해요.

전제 조건

다음 모든 경우 콘텐츠는 다음과 같은 이름의 셸 변수에 있다고 가정합니다.s:

s='CONTAINER|CPU%|MEMUSAGE/LIMIT|MEM%|NETI/O|BLOCKI/O|PIDS
nginx_container|0.02%|25.09MiB/15.26GiB|0.16%|0B/0B|22.09MB/4.096kB|0'

What(현대 jq)

# thanks to @JeffMercado and @chepner for refinements, see comments
jq -Rn '
( input  | split("|") ) as $keys |
( inputs | split("|") ) as $vals |
[[$keys, $vals] | transpose[] | {key:.[0],value:.[1]}] | from_entries
' <<<"$s"

방법(현대 jq)

이것은 매우 새로운 것을 필요로 합니다(약 1.5). jq촘촘한 코드 덩어리입니다.분석 방법:

  • 사용.-n막다jq입력 스트림 전체를 읽을 수 있도록 남겨두고 stdin을 스스로 읽습니다.input그리고.inputs-- 전자는 한 줄을 읽고 후자는 나머지 모든 줄을 읽습니다.(-Rraw 입력의 경우 JSON 오브젝트가 아닌 텍스트 행이 읽힙니다).
  • 와 함께[$keys, $vals] | transpose[], 생성 중입니다.[key, value]쌍(Python 용어로 두 목록의 압축을 푼다).
  • 와 함께{key:.[0],value:.[1]}, 각각을 만들고 있습니다.[key, value]그 형식의 물체로 짝을 짓다.{"key": key, "value": value}
  • 와 함께from_entries이러한 쌍을 이러한 키와 값을 포함하는 개체로 결합합니다.

What(셸 지원)

이것은 상당히 오래된 시스템에서 작동합니다.jq위의 방법보다 높고, 네이티브가 다음과 같은 시나리오에 쉽게 채택되는 접근법이다.jq솔루션 문제 해결이 더 어려워질 수 있습니다.

{
   IFS='|' read -r -a keys # read first line into an array of strings

   ## read each subsequent line into an array named "values"
   while IFS='|' read -r -a values; do

    # setup: positional arguments to pass in literal variables, query with code    
    jq_args=( )
    jq_query='.'

    # copy values into the arguments, reference them from the generated code    
    for idx in "${!values[@]}"; do
        [[ ${keys[$idx]} ]] || continue # skip values with no corresponding key
        jq_args+=( --arg "key$idx"   "${keys[$idx]}"   )
        jq_args+=( --arg "value$idx" "${values[$idx]}" )
        jq_query+=" | .[\$key${idx}]=\$value${idx}"
    done

    # run the generated command
    jq "${jq_args[@]}" "$jq_query" <<<'{}'
  done
} <<<"$s"

방법(쉘 지원)

호출된jq위의 명령어는 다음과 같습니다.

jq --arg key0   'CONTAINER' \
   --arg value0 'nginx_container' \
   --arg key1   'CPU%' \
   --arg value1 '0.0.2%' \
   --arg key2   'MEMUSAGE/LIMIT' \
   --arg value2 '25.09MiB/15.26GiB' \
   '. | .[$key0]=$value0 | .[$key1]=$value1 | .[$key2]=$value2' \
   <<<'{}'

...각 키와 값을 대역 외(JSON으로 구문 분석되지 않고 리터럴 문자열로 처리됨)로 전달한 다음 개별적으로 참조합니다.


결과

위 중 하나가 방출됩니다.

{
  "CONTAINER": "nginx_container",
  "CPU%": "0.02%",
  "MEMUSAGE/LIMIT": "25.09MiB/15.26GiB",
  "MEM%": "0.16%",
  "NETI/O": "0B/0B",
  "BLOCKI/O": "22.09MB/4.096kB",
  "PIDS": "0"
}

왜죠

한마디로 출력으로 유효한 JSON을 생성할 수 있기 때문입니다.

보다 순진한 접근방식을 깨뜨릴 수 있는 예로서 다음 사항을 고려해 주십시오.

s='key ending in a backslash\
value "with quotes"'

물론 예상치 못한 시나리오지만jq대처법을 알고 있습니다.

{
  "key ending in a backslash\\": "value \"with quotes\""
}

...JSON 문자열을 이해하지 못한 구현에서는 다음과 같은 결과가 쉽게 발생할 수 있습니다.

{
  "key ending in a backslash\": "value "with quotes""
}

오래된 포스트인 건 알지만 당신이 찾는 도구는jo: https://github.com/jpmens/jo

간단한 예를 다음에 나타냅니다.

$ jo my_variable="simple"
{"my_variable":"simple"}

조금 더 복잡함

$ jo -p name=jo n=17 parser=false
{
  "name": "jo",
  "n": 17,
  "parser": false
}

어레이 추가

$ jo -p name=jo n=17 parser=false my_array=$(jo -a {1..5})
{
  "name": "jo",
  "n": 17,
  "parser": false,
  "my_array": [
    1,
    2,
    3,
    4,
    5
  ]
}

Jo와 함께 꽤 복잡한 것들을 만들었는데, 좋은 점은 유효하지 않은 json을 만들 가능성에 대해 걱정하면서 솔루션을 굴리는 것에 대해 걱정할 필요가 없다는 것입니다.

도킹업자에게 먼저 JSON 데이터를 제공하도록 요청할 수 있습니다.

docker stats --format "{{json .}}"

상세한 것에 대하여는, https://docs.docker.com/config/formatting/ 를 참조해 주세요.

JSONSTR=""
declare -a JSONNAMES=()
declare -A JSONARRAY=()
LOOPNUM=0

cat ~/newfile | while IFS=: read CONTAINER CPU MEMUSE MEMPC NETIO BLKIO PIDS; do
    if [[ "$LOOPNUM" = 0 ]]; then
        JSONNAMES=("$CONTAINER" "$CPU" "$MEMUSE" "$MEMPC" "$NETIO" "$BLKIO" "$PIDS")
        LOOPNUM=$(( LOOPNUM+1 ))
    else
        echo "{ \"${JSONNAMES[0]}\": \"${CONTAINER}\", \"${JSONNAMES[1]}\": \"${CPU}\", \"${JSONNAMES[2]}\": \"${MEMUSE}\", \"${JSONNAMES[3]}\": \"${MEMPC}\", \"${JSONNAMES[4]}\": \"${NETIO}\", \"${JSONNAMES[5]}\": \"${BLKIO}\", \"${JSONNAMES[6]}\": \"${PIDS}\" }"
    fi 
done

반품:

{ "CONTAINER": "nginx_container", "CPU%": "0.02%", "MEMUSAGE/LIMIT": "25.09MiB/15.26GiB", "MEM%": "0.16%", "NETI/O": "0B/0B", "BLOCKI/O": "22.09MB/4.096kB", "PIDS": "0" }

여기에서는, 다음의 솔루션을 사용하고 있습니다.-R ★★★★★★★★★★★★★★★★★」-s옵션과 함께:

   split("\n")                       # [ "CONTAINER...", "nginx_container|0.02%...", ...]
 | (.[0]    | split("|")) as $keys   # [ "CONTAINER", "CPU%", "MEMUSAGE/LIMIT", ... ]
 | (.[1:][] | split("|"))            # [ "nginx_container", "0.02%", ... ] [ ... ] ...
 | select(length > 0)                # (remove empty [] caused by trailing newline)
 | [$keys, .]                        # [ ["CONTAINER", ...], ["nginx_container", ...] ] ...
 | [ transpose[] | {(.[0]):.[1]} ]   # [ {"CONTAINER": "nginx_container"}, ... ] ...
 | add                               # {"CONTAINER": "nginx_container", "CPU%": "0.02%" ...

json_template='{"CONTAINER":"%s","CPU%":"%s","MEMUSAGE/LIMIT":"%s", "MEM%":"%s","NETI/O":"%s","BLOCKI/O":"%s","PIDS":"%s"}' json_string=$(printf "$json_template" "nginx_container" "0.02%" "25.09MiB/15.26GiB" "0.16%" "0B/0B" "22.09MB/4.096kB" "0") echo "$json_string"

jq를 사용하지 않지만 값에서 arg와 환경을 사용할 수 있습니다.

CONTAINER=nginx_container json_template='{"CONTAINER":"%s","CPU%":"%s","MEMUSAGE/LIMIT":"%s", "MEM%":"%s","NETI/O":"%s","BLOCKI/O":"%s","PIDS":"%s"}' json_string=$(printf "$json_template" "$CONTAINER" "$1" "25.09MiB/15.26GiB" "0.16%" "0B/0B" "22.09MB/4.096kB" "0") echo "$json_string"

표 형식의 데이터로 시작하는 경우 sqawk와 같이 표 형식의 데이터를 기본적으로 사용하여 json으로 만든 다음 jq로 작업하는 것이 더 합리적이라고 생각합니다.

echo 'CONTAINER|CPU%|MEMUSAGE/LIMIT|MEM%|NETI/O|BLOCKI/O|PIDS
nginx_container|0.02%|25.09MiB/15.26GiB|0.16%|0B/0B|22.09MB/4.096kB|0' \
        | sqawk -FS '[|]' -RS '\n' -output json 'select * from a' header=1 \
        | jq '.[] | with_entries(select(.key|test("^a.*")|not))'

    {
      "CONTAINER": "nginx_container",
      "CPU%": "0.02%",
      "MEMUSAGE/LIMIT": "25.09MiB/15.26GiB",
      "MEM%": "0.16%",
      "NETI/O": "0B/0B",
      "BLOCKI/O": "22.09MB/4.096kB",
      "PIDS": "0"
    }

jq,sqawk을 사용법을 사용하다

[
  {
    "anr": "1",
    "anf": "7",
    "a0": "nginx_container|0.02%|25.09MiB/15.26GiB|0.16%|0B/0B|22.09MB/4.096kB|0",
    "CONTAINER": "nginx_container",
    "CPU%": "0.02%",
    "MEMUSAGE/LIMIT": "25.09MiB/15.26GiB",
    "MEM%": "0.16%",
    "NETI/O": "0B/0B",
    "BLOCKI/O": "22.09MB/4.096kB",
    "PIDS": "0",
    "a8": "",
    "a9": "",
    "a10": ""
  }
]

언급URL : https://stackoverflow.com/questions/38860529/create-json-using-jq-from-pipe-separated-keys-and-values-in-bash

반응형