나는 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-content
YAML 문서에서 최상위 섹션을 제거하려면 다음 명령을 사용하십시오 del()
.
질문의 예제 문서를 있는 그대로 고려하면 다음과 같은 YAML 문서가 터미널에 기록됩니다.
/text-content:
post:
operationId: createStaticText
summary: Process text events
description: Process text events
parameters: []
requestBody: null
저장하려면 새 파일로 리디렉션하거나 해당 --in-place
옵션을 사용하여 해당 위치에서 편집하세요(물론 먼저 해당 옵션 없이 테스트한 후).
yq
jq
표현식을 사용하여 jq
YAML 파일을 처리할 수 있도록 하는 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
값입니다. 이것들은 key
value 에서 value
적절한 막대 로 다시 변환 될 수 없으므로 empty
value 로 변경하여 완전히 사라졌습니다. 솔직히 말해서, 나는 이 것의 내부 작동에 대해 완전히 확신하지 못합니다.
이로 인해
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;