awk에서 범위 모드의 범위를 제한하는 방법이 있습니까?

awk에서 범위 모드의 범위를 제한하는 방법이 있습니까?

나는 다음에서 영감을 받아 파일 집합에서 모든 SQL 문을 awk찾기 위해 범위 패턴을 사용하려고 합니다 .select이 stackoverflow 답변.

awk매뉴얼 에서 :

표현의 형태를 pattern1, pattern2일컫는다.범위 모드. 일치하는 레코드로 시작하여 pattern1일치하는 레코드를 pattern2포함하여 모든 입력 레코드를 일치시킵니다.

내 초기 시도는

awk '/select/,/from/' *

이 경우에는 *다양한 파일이 많이 표시됩니다.

이로 인해 selectHTML 태그에 잘못된 히트가 반환되었으므로 다음과 같이 명령을 개선했습니다.

awk '/[^<]select[^>]/,/from/' *

이렇게 하면 대부분의 클릭이 제거되는 것 같습니다.

그러나 주석에 "select"라는 단어가 나타나기 때문에 여전히 일부 잘못된 적중이 발생하며 이러한 적중은 "from"의 마지막 적중 또는 파일 끝 이전의 각 적중에서 많은 라인 노이즈로 이어집니다. 내가 원하는 것은 "select"와 "from" 사이에 10줄 이상이 있으면 범위 패턴이 일치 항목을 등록하지 않는다는 것입니다.

pattern1내 질문은: 일치 항목과 일치 항목 사이의 행 수가 pattern2지정된 임계값을 초과하는 경우 범위 패턴이 일치하지 않도록 할 수 있습니까? 그렇다면 어떻게 달성할 수 있나요?

답변1

범위 모드는 유용하지만 융통성이 없습니다. 이를 사용하지 말고 대신 변수 사이 또는 변수 사이의 상태를 유지하십시오. awk 스크립트 /select/,/from/는 다음과 같습니다.

/select/ {printing = 1}
printing {print}
/from/ {printing = 0}

범위를 여러 행으로 제한하려면 표시된 행의 카운터를 유지하고 표시 여부를 결정할 때까지 출력을 누적합니다.

/select/ {select_text = $0; select_line_count = 1;}
select_line_count {select_text = select_text "\n" $0}
/from/ {if (select_line_count <= 10) {print select_text; print}
        select_line_count = 0}

select줄의 시작 부분(공백 제외)에 있어야 하고 그 뒤에 공백이 와야 하는 등 패턴을 최적화해야 할 수도 있습니다./^[\t ]*select($|[\t ])/

답변2

/pattern1/,/pattern2/{}이런 상황이 발생하면 실행할 블록을 추가하여 필요에 따라 조건을 확장할 수 있습니다 .

예를 들어, 50에서 70 사이의 숫자를 인쇄하면서 각 블록의 처음 5개 일치 항목만 인쇄하는 방법을 살펴보세요.

$ seq 200 | awk '/50/,/70/ {if ($0~/50/) {c=0}; if (c++ <= 5) print}'
50
51
52
53
54
55
150
151
152
153
154
155

귀하의 경우 다음과 같이 말하고 싶을 수도 있습니다. 이렇게 하면 일치하는 처음 10줄이 인쇄됩니다.

awk '/[^<]select[^>]/,/from/ {if (c++ <= 10) print}' *

더 복잡한 솔루션은 이 모든 출력을 저장한 다음 END블록에 인쇄하는 것입니다. 이렇게 하면 특정 행뿐만 아니라 블록 자체를 제어할 수 있습니다. 데이터를 배열 등에 저장합니다.

관련 정보