내용이 포함된 파일이 있습니다.
{
"first_name": "John",
"last_name": "Smith",
"is_alive": true,
"age": 27,
"address": {
"street_address": "21 2nd Street",
"city": "New York",
"state": "NY",
"postal_code": "10021-3100"
},
"phone_numbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [
"Catherine",
"Thomas",
"Trevor"
],
"spouse": null
}
파일 내용이 다음과 같이 보이도록 Busybox 유틸리티를 사용하여 파일의 마지막 } 문자 앞에 내용을 추가하려면 어떻게 해야 합니까?
{
"first_name": "John",
"last_name": "Smith",
"is_alive": true,
"age": 27,
"address": {
"street_address": "21 2nd Street",
"city": "New York",
"state": "NY",
"postal_code": "10021-3100"
},
"phone_numbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [
"Catherine",
"Thomas",
"Trevor"
],
"spouse": null,
"field1": "value1",
"field2": "value2",
"field3": "value3",
"field4": "value4"
}
그러나 } 문자가 반드시 파일의 마지막 문자나 마지막 줄에 있을 필요는 없습니다.
지금까지 나는 이 해결책을 찾았습니다.
tac file2 | sed '0,/}/s/}/}\n"field4": "value4"\n"field3": "value3",\n"field2": "value2",\n"field1": "value1",\n,/' | tac>tmp_file && mv tmp_file file2
답변1
awk 및 Bourne과 유사한 쉘을 사용하십시오.
$ cat tst.sh
#!/usr/bin/env bash
new='\
"field1": "value1",
"field2": "value2",
"field3": "value3",
"field4": "value4"\
'
awk '
{ lines[NR] = $0 }
$0 == "}" { last = NR - 1 }
END {
for ( i=1; i<last; i++ ) {
print lines[i]
}
print lines[i] ","
indent = lines[i]
sub(/[^ \t].*/,"",indent)
gsub(/(^|\n)/,"&"indent,new)
print new
for ( ++i; i<=NR; i++ ) {
print lines[i]
}
}
' new="$new" file
$ ./tst.sh file
{
"first_name": "John",
"last_name": "Smith",
"is_alive": true,
"age": 27,
"address": {
"street_address": "21 2nd Street",
"city": "New York",
"state": "NY",
"postal_code": "10021-3100"
},
"phone_numbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [
"Catherine",
"Thomas",
"Trevor"
],
"spouse": null,
"field1": "value1",
"field2": "value2",
"field3": "value3",
"field4": "value4"
}
새 블록의 들여쓰기는 바로 앞 줄의 들여쓰기로 설정되므로 해당 들여쓰기를 하드코딩할 필요가 없으며 뒤에 주석 줄이나 빈 줄이 있어도 작동합니다. 마지막 }
줄.
답변2
이 ed
유틸리티를 사용하십시오(컨테이너에서 테스트됨 BusyBox
).
ed file<<EOF
$ i
,
"field1": "value1",
"field2": "value2",
"field3": "value3",
"field4": "value4"
.
w
q
EOF
cat file
출력 파일이 통과합니다.잭시험.
답변3
마지막 }이 마지막 줄인 경우 head 명령을 사용하여 수행할 수 있습니다. 추가된 텍스트에 마지막 }을 포함합니다.
$ cat addit
"field1": "value1",
"field2": "value2",
"field3": "value3",
"field4": "value4"
}
그리고 당신이 원하는 것은 :
$ (head -n -1 input_file ;cat addit)
추가된 텍스트에서 마지막 }를 생략하고 대신 위 출력을 이 sed로 파이프합니다.
$ sed '$ a \}'
답변4
참고: 이 답변은 Busybox 멀티 바이너리에 내장된 유틸리티만 사용하는 것으로 제한되지 않습니다.jq
유틸리티. 이 잘 알려진 JSON 처리 도구는 대부분의 일반적인 아키텍처에 대한 정적 바이너리로 제공되므로 설치나 권한 업그레이드가 필요하지 않습니다. 공개 Docker 이미지를 통해서도 사용할 수 있습니다.
Busybox 멀티 바이너리에는 사용되는 Busybox에 따라 매우 다양한 수의 내장 유틸리티가 포함될 수 있기 때문입니다(Alpine Linux에서는 302개의 유틸리티, 공용 Busybox Docker 이미지에서는 추가로 100개의 유틸리티). 질문, 나는 그 한계가 순전히 인위적이며 그다지 중요하지 않다고 가정하고 있습니다.
일단 설치되면 jq
새 데이터를 제공하는 형식에 따라 다양한 방법으로 데이터를 추가할 수 있습니다.
별도의 키와 인코딩되지 않은 문자열이 있다고 가정하면 jq
with를 사용하여 --arg key value
각 문자열을 인코딩하고 내부 jq
변수를 생성합니다. --argjson
이미 적절하게 인코딩된 값(숫자, 부울, JSON 문자열 또는 JSON 조각)의 경우 를 사용합니다 --arg
. 그런 다음 표현식 내에서 $
( .$key1
$var2
$lastname
jq
$ARGS.named
jq --arg field1 value1 \
--arg field2 'value2 ("temporarily")' \
--arg field3 value3 \
--argjson field4 true \
--argjson field5 '{ "some json fragment": [ "goes", "here" ] }' \
'. += $ARGS.named' file.json
의 첫 번째 예제 문서의 경우 file.json
다음이 생성됩니다.
{
"first_name": "John",
"last_name": "Smith",
"is_alive": true,
"age": 27,
"address": {
"street_address": "21 2nd Street",
"city": "New York",
"state": "NY",
"postal_code": "10021-3100"
},
"phone_numbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [
"Catherine",
"Thomas",
"Trevor"
],
"spouse": null,
"field1": "value1",
"field2": "value2 (\"temporarily\")",
"field3": "value3",
"field4": true,
"field5": {
"some json fragment": [
"goes",
"here"
]
}
}
.
분명히 위의 표현식과 다른 경로를 지정하여 문서에 데이터를 삽입할 위치를 결정할 수 있습니다. 예를 들어, "212"로 시작하는 집 전화번호가 하나 이상 있는 사람을 나타내는 입력 객체에 데이터를 추가하려면 다음을 수행하세요.
select(
.phone_numbers |
map(.type == "home" and (.number | startswith("212"))) |
any
) += $ARGS.named