많은 레코드가 있는 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
있는 개체 모음 )으로 변환하고 숫자 배열 인덱스를 키인 헤더로 바꿉니다.key
value
map()
$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를 사용하십시오.Date
Region
REGION
,
$ 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