sed
다음과 같이 긴 파일(Junos 구성)에서 중괄호로 구분된 구성 청크를 추출 하려고 합니다 .
group foo {
command;
setting {
value;
}
command;
}
}
첫 번째 들여쓰기 줄과 같은 위치 에서 멈추는 것이 비결입니다 .
sed
한 패턴에서 다른 패턴으로 매칭을 사용하는 방법을 배웠습니다 ., 다음을 시도했습니다.
$ sed -rn '/^( *)group foo/,/^\1\}/p' config.txt
sed: -e expression #1, char 41: Invalid back reference
문제는 두 개의 별도 스키마와 역참조가 둘 사이에서 작동하지 않는다는 /^( *)group foo/
것 입니다. /^\1\}/
그렇다면 어떻게 이를 달성할 수 있습니까?
답변1
당신 말이 맞아요: 그래도역참조는 기본 정규식에 정의되어 있습니다.(갈아 바수다)(각 sed 주소는 BRE이므로, 역참조를 지원함), 역참조는 다른 BRE에 정의된 캡처링 그룹을 검색할 수 없습니다. 따라서 이 주소의 캡처 그룹은 /^( *)group foo/
다른 주소에서 검색할 수 없습니다 /^\1\}/
.
이는 test.awk
여는 중괄호와 닫는 중괄호를 계산하여 수행됩니다.
brk && /\{/{brk++} #Increment brk if brk is not zero and line contains {
brk && /\}/{brk--} #Decrement brk if brk is not zero and line contains }
/^[[:blank:]]*group foo \{/{brk=1;prt=1} #Set brk and prt if match initial pattern
prt #Print line if prt is set
!brk && prt{prt=0} #If brk is zero and prt is not, set prt=0
$ cat file
foo bar
foo bar2
}
group foo {
command;
setting {
value;
}
command;
}
dri {
}
end
$ awk -f test.awk file
group foo {
command;
setting {
value;
}
command;
}
또 다른 덜 우아한 옵션은 빈 공간을 계산하는 것입니다. 이것이 바로 시도의 배경이 되는 아이디어입니다. 들여쓰기에 탭이 있으면 깨집니다.
/^ *group foo \{/{
match($0,/^ */) #Sets RLENGTH to the length in characters of the matched string
i=RLENGTH
}
i #If i is set, the current line is printed
i&&/^ *\}$/{
match($0,/^ */) #Again, sets RLENGTH to the length of the matched string
if(RLENGTH==i){i=0} #If the value is equal to the one from group foo line, unset i
}
답변2
역참조는 에서 사용할 수 있지만 /pattern/
이러한 표현식에서 다른 표현식으로 기억되지는 않습니다.
예를 들어 sed에는 다음과 같은 많은 솔루션이 있습니다(GNU sed 사용).
sed -rz 's@.*\n(( *)group foo.*\2}).*@\1@;s@^(( *).*)@\1\2@;s@(\n( *)}).*\2$@\1\n@' config.txt
이 -z
플래그는 패턴 공간에 전체 구성을 로드하는 데 사용됩니다. 첫 번째는 s
적절한 들여쓰기를 사용하여 마지막 닫는 괄호(greedy*) 시작 전후의 모든 내용을 제거합니다.group foo
두 번째는 s
들여쓰기를 끝까지 복사합니다. 마지막 것은 s
적절한 들여쓰기로 첫 번째 닫는 괄호 뒤의 모든 것을 제거합니다. 이 마지막 두 명령은 관심 있는 구성 블록과 동일한 들여쓰기 수준에 여러 구성 블록이 있는 경우에만 필요합니다.
답변3
sed
스키마 전반에 걸쳐 역참조를 사용할 수 있는 편리함을 제공하지는 않지만 단일 스키마 공간에 두 줄을 넣은 다음 역참조를 찾을 수 있습니다.
$ sed -Ene '
/^\s+group foo \{$/,$!d
p;/^\s+group foo \{$/h;/\}/!d
G;/^(\s+)\S.*\n\1\S/q
' file
사용된 Sed 명령:
p
패턴 공간의 내용을 인쇄합니다.$!d
마지막 행이 아닌 한 행을 삭제한다는 의미입니다. 그러나 여기서는 범위 연산자를 사용하므로 범위 밖의 모든 행이 삭제된다는 의미입니다. 범위는 foo 그룹 행부터 eof까지입니다. 따라서 기본적으로 첫 번째 foo 행 세트 이전의 모든 행을 건너뜁니다.G
예약된 공간의 내용을 패턴 공간에 추가합니다.q
추가 처리를 중지한다는 의미입니다. 종료와 유사합니다.
또 다른 접근 방식은 먼저 시작선을 식별한 다음 뒤따르는 중괄호의 중첩 깊이를 계속 인쇄 및 기록하고 중첩 깊이가 0에 도달하면 중지하는 것입니다.
$ sed -ne '/^\s*group foo \{$/,${
p;// {x;s/.*//;x;}
/\{/ {x;s/^/./;x;}
/\}/ {x;s/^.//;x;}
/\}/G;/\n$/q
}' file
perl
공백을 일치시키려는 경우 사용하기가 거의 쉽지 않습니다.
$ perl -lne 'print if /^(\s+)(?{ $k=$1 })group\s+foo\s+\{/x ... /^$k\}/' file