2개 이상의 연속 행에 특정 패턴이 포함된 경우 일치하는 행을 모두 삭제하고 첫 번째 행만 유지합니다.
아래 예에서 2개 이상의 연속 행에 "논리적 IO"가 포함된 경우 일치하는 모든 행을 삭제하고 첫 번째 행은 유지해야 합니다.
입력 파일:
select * from test1 where 1=1
testing logical IO 24
select * from test2 where condition=4
parsing logical IO 45
testing logical IO 500
handling logical IO 49
select * from test5 where 1=1
testing logical IO 24
select * from test5 where condition=78
parsing logical IO 346
testing logical IO 12
결과물 파일:
select * from test1 where 1=1
testing logical IO 24
select * from test2 where condition=4
parsing logical IO 45
select * from test5 where 1=1
testing logical IO 24
select * from test5 where condition=78
parsing logical IO 346
답변1
사용 awk
:
awk '/logical IO/ {if (!seen) {print; seen=1}; next}; {print; seen=0}' file.txt
/logical IO/ {if (!seen) {print; seen=1}; next}
행이 포함되어 있는지 확인하고logical IO
변수가seen
false인 경우, 즉 이전 행이 포함되지 않은 경우logical IO
행을 인쇄하고 설정seen=1
하고 다음 행으로 이동합니다. 그렇지 않으면 이전 행이 이미 포함되어 있으므로 다음 행으로 이동합니다.logical IO
다른 행의 경우
{print; seen=0}
행과 세트를 인쇄합니다.seen=0
예:
$ cat file.txt
select * from test1 where 1=1
testing logical IO 24
select * from test2 where condition=4
parsing logical IO 45
testing logical IO 500
select * from test5 where 1=1
testing logical IO 24
select * from test5 where condition=78
parsing logical IO 346
parsing logical IO 346
testing logical IO 12
$ awk '/logical IO/ {if (!seen) {print; seen=1}; next}; {print; seen=0}' file.txt
select * from test1 where 1=1
testing logical IO 24
select * from test2 where condition=4
parsing logical IO 45
select * from test5 where 1=1
testing logical IO 24
select * from test5 where condition=78
parsing logical IO 346
답변2
그리고 sed
:
sed '/logical IO/{x;//!{g;p;};d;};//!h' infile
작동 방식:
sed '/logical IO/{ # if line matches
x # exchange hold space w. pattern space
//!{ # if whatever was in the hold buffer doesn't match
g # overwrite pattern space with hold space content
p # print current pattern space
}
d # delete
}
//!h # if line doesn't match, copy over the hold space
' infile
답변3
내부에TxR상태 변수를 변경하지 않고도 이를 표현할 수 있습니다. 파일의 특정 위치에서 두 가지 분기 방법을 사용하여 여러 줄 패턴 일치를 수행할 수 있습니다. 검색 문자열이 포함된 하나 이상의 연속 줄을 일치시켜 첫 번째 줄을 인쇄하거나, 한 줄을 일치시켜 인쇄합니다. 한 가지 가능한 접근 방식은 다음과 같습니다.
@(repeat)
@ (cases)
@ (collect :gap 0 :mintimes 1)
@line
@ (require (search-str line "logical IO"))
@ (end)
@ (do (put-line (first line)))
@ (or)
@line
@ (do (put-line line))
@ (end)
@(end)
달리기:
$ txr 첫 번째 로그 IO.txr 데이터 1=1인 test1에서 *를 선택합니다. 논리 IO 24 테스트 SELECT * FROM test2 여기서 조건=4 논리적 IO 구문 분석 45 1=1인 test5에서 *를 선택합니다. 논리 IO 24 테스트 SELECT * FROM test5 여기서 조건=78 논리적 IO 346 구문 분석
@(repeat)
변수 바인딩을 수집하지 않고 데이터를 반복하는 프로시저를 구축합니다. 이 구성을 보면 일반적으로 반복 중에 일부 부작용이 발생함을 나타냅니다. 이 경우에는 출력입니다.
내부적으로는 분리된 케이스로 구성된 다중 경로 일치라는 구조가 @(repeat)
있습니다 . 두 번째 분기인 대체 사례는 단순히 한 줄과 일치합니다. 다음 지침은 이 줄을 인쇄합니다.@(cases)
@(or)
@line
@(do (put-line (first line)))
조직의 주요 부서 @(cases)
는 자료를 수집하는 것입니다 @(collect)
. 의 요구 사항에 따르면 일치 항목은 연속적이어야 하며 :gap 0
의 요구 사항에 따라 일치 항목이 하나 이상 있어야 합니다 :mintimes 1
. 컬렉션 본문은 변수에 바인딩된 한 줄과 일치합니다 line
. 그런 다음 @(require ...)
줄에 하위 문자열이 포함되어 있지 않으면 실패하는 어설션이 있습니다 "logical IO"
. 따라서 일치하지 않는 행을 발견하면 컬렉션 :gap 0
을 건너뛰는 것을 방지하기 때문에 컬렉션이 중지됩니다. 일치하는 행은 line
팝되는 목록으로 암시적으로 수집됩니다 collect
(컬렉션 내부에 바인딩된 변수는 자동으로 컬렉션 외부의 목록이 되며 여러 반복에 걸쳐 바인딩된 모든 값을 포함합니다). 필요에 따라 첫 번째 것만 인쇄하고 나머지는 억제합니다.
이 두 @line
일치 항목은 서로 아무 관련이 없습니다. line
서로 다른 범위의 변수를 바인딩합니다.
또 다른 접근 방식은 TXR Lisp의 게으른 목록을 사용하여 일부 기능적 프로그래밍을 수행하는 것입니다.
[(opip (partition-by (do cond
((search-str @1 "logical IO") t)
(t @1)))
(mapcar* first)
put-lines)
(get-lines)]
$ txr 첫 번째 로그 IO.tl
연산자는 opip
함수 파이프라인을 구축하기 위한 구문 설탕입니다. 해당 인수는 op
암시적으로 번호가 매겨진 인수로 익명 함수를 생성하기 위한 구문: 매크로 로 처리됩니다 .
전체 형식은 [(opip ...) (get-lines)]입니다. 이는 "결과 함수를 호출 opip
하고 결과를 (get-lines)
인수로 전달"을 의미합니다. 이는 (get-lines)
표준 입력 스트림을 게으른 문자열 목록으로 변환합니다. (그것의 "반대"는 put-lines
그것이 나타난다는 것입니다).
이제 파이프라인에서 partition-by
(lazy!)를 사용하여 행 목록을 해당 파티션인 목록 목록으로 변환합니다. 분할 조건은 포함된 각 행이 logical IO
기호에 매핑되고 t
다른 모든 행은 자신에게만 매핑된다는 것입니다. 이는 연속된 행이 logical IO
하나의 파티션으로 나타나고 다른 모든 행은 길이가 1인 파티션으로 나타남을 의미합니다. 이제 이 데이터로 해야 할 일은 각 파티션을 첫 번째 항목에 매핑하고 이를 전달한 후 덤프 결과를 (mapcar* first)
전달하는 것뿐입니다 .put-lines
우리는 모든 것이 게으르게 실행되어 실제로 에 의해 실행되기를 원하기 mapcar*
때문에 이를 사용합니다 . 출력 목록을 반복할 때 lazy 에서 항목을 가져와 결과 목록에서 해당 행을 읽기 위해 I/O가 발생하도록 합니다.mapcar
put-lines
put-lines
mapcar*
partition-by
(get-lines)
정규식을 잘못 사용 하면 mapcar
덤프되기 전에 전체 출력이 메모리에 빌드되는 문제가 발생할 수 있으며 이는 대용량 파일에 대한 나쁜 신호입니다.