Busybox 유틸리티를 사용하여 파일의 마지막 } 문자 앞에 콘텐츠를 추가하려면 어떻게 해야 합니까?

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
}

파일 내용이 다음과 같이 보이도록 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새 데이터를 제공하는 형식에 따라 다양한 방법으로 데이터를 추가할 수 있습니다.

별도의 키와 인코딩되지 않은 문자열이 있다고 가정하면 jqwith를 사용하여 --arg key value각 문자열을 인코딩하고 내부 jq변수를 생성합니다. --argjson이미 적절하게 인코딩된 값(숫자, 부울, JSON 문자열 또는 JSON 조각)의 경우 를 사용합니다 --arg. 그런 다음 표현식 내에서 $( .$key1$var2$lastnamejq$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

관련 정보