YAML 파일에서 특정 헤더의 특정 하위 섹션을 모두 제거하는 방법은 무엇입니까?

YAML 파일에서 특정 헤더의 특정 하위 섹션을 모두 제거하는 방법은 무엇입니까?

나는 bash 쉘을 사용하고 있습니다. 특정 텍스트 블록을 제거하려는 YAML 파일이 있습니다.

  /image-content:
    post:
      operationId: createEventPublic
      summary: Process events
      description: Process events
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Content'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Content'
  /text-content:
    post:
      operationId: createStaticText
      summary: Process text events
      description: Process text events
      parameters: []
      requestBody:
    ...

예를 들어 경로에 "이미지 콘텐츠"가 포함된 텍스트 블록을 제거하고 싶습니다. 일반적으로 이 기능을 사용하여 해당 텍스트가 포함된 한 줄을 삭제할 수 있습니다.

sed -i '/image-content/d' ./infile

하지만 다음 줄이 두 개의 공백과 "/"(예: "/")로 시작될 때까지 그 이후의 모든 줄을 어떻게 바꾸는지 잘 모르겠습니다. 위의 경우까지 모든 것을 제거하고 싶습니다.

  /text-content:

편집하다:이것은 유효한 openapi 3 swagger가 아닐 수도 있지만 여전히 유효한 YAML 파일이라고 생각합니다.

openapi: 3.0.0
components:
  /static/image-content:
    post:
      type: hello
  /api/hello:
    post:
      type: hello
  /static/css-content:
    post:
      type: hello

궁극적으로 "/static"으로 시작하는 블록을 제거하고 싶습니다. 따라서 최종 문서는 다음과 같습니다.

openapi: 3.0.0
components:
  /api/hello:
    post:
      type: hello

답변1

yq -y 'del(."/image-content")' file.yml

이것은 yq다음에서 사용됩니다.https://kislyuk.github.io/yq//image-contentYAML 문서에서 최상위 섹션을 제거하려면 다음 명령을 사용하십시오 del().

질문의 예제 문서를 있는 그대로 고려하면 다음과 같은 YAML 문서가 터미널에 기록됩니다.

/text-content:
  post:
    operationId: createStaticText
    summary: Process text events
    description: Process text events
    parameters: []
    requestBody: null

저장하려면 새 파일로 리디렉션하거나 해당 --in-place옵션을 사용하여 해당 위치에서 편집하세요(물론 먼저 해당 옵션 없이 테스트한 후).

yqjq표현식을 사용하여 jqYAML 파일을 처리할 수 있도록 하는 JSON 구문 분석기의 래퍼입니다 .


해당 문서가 다음과 같은 경우부분의실제 구조를 표시하지 않는 경우(두 개의 들여쓰기 공백은 두 번째 수준 섹션이 표시됨을 의미함) 다음을 사용할 수 있습니다.

yq -y 'del(.[]."/image-content")' file.yml

.[]."/image-content"표현은 " /image-content최상위 레이어 아래의 모든 것"을 나타냅니다.

도착하다재귀적으로/image-content섹션이 문서의 어디에 나타나든 검색하고 삭제하려면 다음 을 사용하세요.

yq -y 'del(.. | ."/image-content"?)' file.yml

에 사용된 표현식은 del()문서 구조를 재귀적으로 탐색하여 명명된 섹션 이 있는 ..모든 섹션을 추출합니다 (이는 XPath 쿼리의 연산자에 해당). 그런 다음 해당 내용을 삭제하십시오./image-content//


업데이트된 질문을 해결하려면:

yq -y '.components |= with_entries(del(select(.key | startswith("/static/"))) // empty)' file.yml

components그러면 하위 섹션을 가져오고 임시로 개별 key합계 value값으로 변환하고( 설명서 with_entries()문서 참조 jq) 키가 정확한 문자열로 시작하는 섹션을 선택 및 제거하여 섹션 이 업데이트됩니다 /static/.

비트 // empty: del()연산의 결과가 null값입니다. 이것들은 keyvalue 에서 value적절한 막대 로 다시 변환 될 수 없으므로 emptyvalue 로 변경하여 완전히 사라졌습니다. 솔직히 말해서, 나는 이 것의 내부 작동에 대해 완전히 확신하지 못합니다.

이로 인해

openapi: 3.0.0
components:
  /api/hello:
    post:
      type: hello

답변2

시험용 GNU sed:

sed -n '
    /^\s*\/static/ {
        n
        :c
            /^[[:space:]]*\//! {
                n
                bc
            }
        }
    p
' data

따라서 두 번째 질문은 기본적으로 동일합니다.

sed -n '
    /^[[:space:]]\+\/image-content:$/ {
        n
        :c
            /^[[:space:]]\+\//! {
                n
                bc
            }
    }
    p
' data

첫 번째 줄은 원하는 단락을 찾은 다음 새 단락을 찾을 때까지 각 줄을 반복하고 삭제합니다. 물론 -i내부 편집을 위해 플래그를 삽입할 수도 있습니다.

답변3

일반 솔루션:일치하는 줄과 들여쓰기된 줄을 모두 삭제하세요.

특정 형식의 파일이 있는 경우 일반적으로 해당 형식에 맞게 특별히 설계된 도구를 사용하는 것이 가장 좋습니다. 귀하의 경우 줄 들여쓰기를 위한 공백을 기반으로 하는 간단한 규칙이 있는 것 같으니 표준 도구에 대한 간단한 스크립트를 제공하는 것은 어떨까요?

sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\/image-content/{s/^\( *\).*/ \1/;x;d;}' file

하는 일: 일치하는 패턴의 줄이 발견되면 예약된 공간에 공백 수만큼 저장하고 공백 하나를 추가하면서 삭제합니다. 그런 다음 각 줄에 대해 최소한 유지 버퍼만큼의 공백으로 시작하는지 확인합니다. 그렇다면 들여쓰기가 적은 줄이 유지 공간을 재설정할 때까지 해당 줄도 제거합니다.

자세한 설명

  • H;x현재 행을 H이전 공간에 추가하고 공간을 교환하므로 이제 현재 행은 예약된 공간에 유지되고 패턴 공간에서는 이전 예약된 공간에 추가된 행을 확인할 수 있습니다.
  • /^\( *\)\n\1/예약된 공간에 최소한 하나의 공간이 있고 현재 라인에 최소한 예약된 버퍼만큼의 공간이 있음을 식별하는 패턴입니다. 즉, 다음 줄을 삭제해야 하며 이 {}줄은 이 경우에만 실행된다는 의미입니다.
  • s/\n.*//개행 문자로 시작하는 모든 항목을 지우므로 추가 줄을 제거하고 이전에 보유했던 버퍼에 있던 내용을 복원합니다. 이제 x버퍼를 다시 변경하여 이전 상태로 돌아가고 d현재 패턴 공간을 삭제하여 새 루프를 시작할 수 있습니다.
  • 나머지 스크립트는 행이 삭제되지 않은 경우에만 실행됩니다. s/.*//;x패턴 공간을 지우고 공간을 바꾸면 초기 상태가 됩니다. 현재 행은 패턴 공간에 있고 예약된 공간은 비어 있습니다.
  • 마지막으로 섹션의 트리거를 삭제해야 합니다. \/image-content모든 트리거 모드가 될 수 있습니다. 물론 그럴 수도 있고 \/static그럴 수도 있습니다.모든 들여쓰기 수준에서. 따라서 이후의 모든 작업은 트리거 라인에서만 수행됩니다. 다른 모든 줄은 단순히 인쇄됩니다.
  • s/^\( *\).*/ \1/;x이 줄의 모든 공백을 제거하고 다른 공백을 추가한 후 향후 비교를 위해 예약된 공간에 배치합니다(스크립트 시작 부분에서 수행한 작업). 그런 다음 d출력을 방지하려면 삭제 해야 합니다 .

답변4

  • 댓글 없음
sed '/^ *\/image-content:/{
:sub;
  $b eof;
  N;
/^\( *\)[^ ].*\n\1[^ ][^\n]*$/!b sub;
:eof;
  s/^\( *\)[^ ].*\n\(\1[^ ][^\n]*\)$/\2/;
  t loop;
  d;
:loop; n; b loop;
}' file;
  • 댓글이 있습니다
sed '/^ *\/image-content:/{
:sub;
  $b eof;  # end of file
  N;
/^\( *\)[^ ].*\n\1[^ ][^\n]*$/!b sub;  # leading-spaces==ending-spaces(\1). loop if not same level
:eof;
  # if join with the first-line of next block, only leave the joint-line.
  s/^\( *\)[^ ].*\n\(\1[^ ][^\n]*\)$/\2/;
  t loop;  # jump if s/././ is done
  d;  # no more lines after target block
:loop; n; b loop;  # b loop is to speed the process
}' file;

관련 정보