sed가 범위 정의 패턴 내에서 역참조를 만들 수 있나요?

sed가 범위 정의 패턴 내에서 역참조를 만들 수 있나요?

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

관련 정보