Unix에서 jq를 사용하여 테이블 레코드를 JSON 파일로 변환

Unix에서 jq를 사용하여 테이블 레코드를 JSON 파일로 변환

많은 레코드가 있는 Linux 시스템에 테이블이 있습니다. 다음을 얻기 위해 쿼리를 실행하고 있습니다.

select * from TABNAME_XYZ


CID CN    XY     NAT   UIC    DATE        Region
12  2123  120.9  29.0  100.0  2018-06-08  JAIPUR
13  0987  78.9   100.3 28.8   2020-12-09  DELHI

출력을 JSON으로 변환하는 쉘 스크립트를 작성하고 싶지만 어디서부터 시작해야 할지, 무엇을 해야 할지 잘 모르겠습니다. JSON은 다음과 같아야 합니다.

{"CID":"12","CN":"2123","DATA":{"XY":120.9,"NAT":29.0,"UIC":100.0,"Date":"2018-06-08","REGION":"JAIPUR"}},
{"CID":"13","CN":"0987","DATA":{"XY":78.9,"NAT":100.3,"UIC":28.8,"Date":"2020-12-09","REGION":"DELHI"}}

jq이미 내 시스템에 있습니다.

답변1

필드가 항상 지정된 순서대로 있고 입력의 첫 번째 줄에 헤더 행이 있고 여러 공백 문자가 필드를 구분한다고 가정하면 압축된 연속 공백을 사용하고 를 사용하여 tr데이터를 구문 분석할 수 있습니다 jq.

database-client-command |
tr -s ' ' |
jq -c -Rn '
        input  | split(" ") as $head |
        inputs | split(" ") |
                to_entries |
                        map(.key = $head[.key]) |
                        [ .[:2][], { key: "DATA", value: (.[2:] | from_entries) } ] |
                from_entries'

이 표현식은 별도의 행에서 jq원시 데이터를 읽습니다 .tr

첫 번째 행은 헤더로 분할되어 의 배열에 저장됩니다 $head.

헤더에서 했던 것처럼 나머지 행을 배열로 분할합니다. 필터는 각 배열을 "입력 형식"( 키가 to_entries있는 개체 모음 )으로 변환하고 숫자 배열 인덱스를 키인 헤더로 바꿉니다.keyvaluemap()$head

그런 다음 map()필터는 배열을 다시 정렬하여 세 번째 요소를 별도의 DATA하위 개체로 이동하고 "항목 양식"에서 다시 변환합니다.

키와 데이터가 재배열되면 from_entries필터는 "입력 양식"에서 배열을 반환합니다.

스크립트의 출력은 일련의 JSON 개체가 되며, 질문에 데이터가 주어지면 이러한 개체는 다음과 같습니다.

{"CID":"12","CN":"2123","DATA":{"XY":"120.9","NAT":"29.0","UIC":"100.0","DATE":"2018-06-08","Region":"JAIPUR"}}
{"CID":"13","CN":"0987","DATA":{"XY":"78.9","NAT":"100.3","UIC":"28.8","DATE":"2020-12-09","Region":"DELHI"}}

Region으로 REGION변경 하려면 데이터베이스를 쿼리하는 동안 또는 사후 처리 단계로 이 작업을 수행하는 것이 좋습니다 DATE.Date

첫 번째 줄의 후행 쉼표로 인해 예상 결과는 유효한 JSON이 아닙니다.

답변2

실제로 와 DATE로 변환 하고 싶지 않고 (만약 그렇게 하는 경우 변경할 태그를 선택하는 논리를 설명하면 간단한 조정임) 다음을 제외하고 각 출력 라인의 끝에서 과 로 변환하고 싶다고 가정합니다. 마지막(다시 말하지만, 이렇게 하지 않으면 간단한 조정입니다) 그런 다음 모든 Unix 시스템의 모든 쉘에서 awk를 사용하십시오.DateRegionREGION,

$ cat tst.awk
NR==1 {
    split($0,tags)
    next
}
{
    printf "%s{%s,%s,\"DATA\":{", sep, fmt(1), fmt(2)
    for (i=3; i<=NF; i++) {
        printf "%s%s", fmt(i), (i<NF ? "," : "}}")
    }
    sep = ",\n"
}
END {
    print ""
}
function fmt(fldNr,     tag, val) {
    tag = tags[fldNr]
    val = $fldNr
    gsub(/"/,"\\\"",val)
    return sprintf("\"%s\":\"%s\"", tag, val)
}

$ awk -f tst.awk file
{"CID":"12","CN":"2123","DATA":{"XY":"120.9","NAT":"29.0","UIC":"100.0","DATE":"2018-06-08","Region":"JAIPUR"}},
{"CID":"13","CN":"0987","DATA":{"XY":"78.9","NAT":"100.3","UIC":"28.8","DATE":"2020-12-09","Region":"DELHI"}}

답변3

이것은 한 가지 방법입니다. 다음을 다음과 같이 저장합니다 foo.awk.

{
  if(NR==1){
    for(i=1;i<=NF;i++){
      head[i]=$i
    }
  }
  else{
    printf "{\"%s\":\"%s\",\"%s\":\"%s\",\"DATA\":{\"%s\":%s,\"%s\":%s,\"%s\":%s,\"%s\":\"%s\",\"%s\":\"%s\"}}\n", head[1],$1,head[2],$2,head[3],$3,head[4],$4,head[5],$5,head[6],$6,head[7],$7;

  }
}

그런 다음:

$ cat file |  awk -f foo.awk
{"CID":"12","CN":"2123","DATA":{"XY":120.9,"NAT":29.0,"UIC":100.0,"DATE":"2018-06-08","Region":"JAIPUR"}}
{"CID":"13","CN":"0987","DATA":{"XY":78.9,"NAT":100.3,"UIC":28.8,"DATE":"2020-12-09","Region":"DELHI"}}

여기에서는 명령의 출력을 select파일에 저장했습니다 file. 귀하의 경우 데이터베이스에 있는 명령줄 클라이언트를 사용하면 됩니다. 예를 들어, mySQL을 사용하면 다음과 같습니다.

mysql -e 'select * from TABNAME_XYZ' | awk -f foo.awk

관련 정보