grep이 일치하지 않게 하려는 텍스트 파일과 패턴이 있습니다. 문제는 이전 행도 일치하지 않기를 원한다는 것입니다.
내 파일:
line 1
line 2
pattern
line 4
나는 그것을 시도했고 cat file | grep -v pattern
결과는 다음과 같습니다.
line 1
line 2
line 4
그런 다음 시도해 보았는데 cat file | grep -B 1 pattern
결과는 다음과 같습니다.
line 2
pattern
그러나 함께 사용하면 다음과 같은 결과를 cat file | grep -v -B 1 pattern
얻습니다.
line 2
출력을 어떻게 만들 수 있습니까?
line 1
line 4
답변1
나는 grep
파일에서 한 줄을 추출할 때만 이 도구를 사용하는 경향이 있으므로 텍스트에서 더 복잡한 편집을 수행해야 할 때는 다른 도구를 사용합니다.
여기의 모든 솔루션은 패턴이 텍스트에서 여러 번 나타날 수 있다고 가정하고 패턴이 발생하는 줄과 바로 앞의 줄을 삭제합니다. 처음 두 솔루션은 패턴이 연속된 라인에서 일치하는 경우 문제가 발생합니다.
sed
패턴을 일치시키고 /pattern/
명령 N
및 를 트리거하도록 할 수 있습니다 d
. 이 명령은 다음 줄을 버퍼에 추가한 다음 두 가지를 모두 삭제합니다.
sed '/pattern/ { N; d; }' file
왜냐하면 당신은 그 줄을 버리고 싶기 때문입니다앞으로패턴을 일치시키기 위해 데이터를 거꾸로 입력합니다 sed
. 마지막 줄에서 시작하여 파일의 시작 부분으로 이동합니다. sed
완료되면 데이터를 다시 반전시킵니다.
tac file | sed '/pattern/ { N; d; }' | tac
이 tac
유틸리티는 GNU coreutils의 일부입니다. 대부분의 비 GNU 시스템을 tail -r
대신 사용할 수 있습니다 tac
( tail(1)
설명서를 확인하세요).
패턴이 두 개의 연속 행과 일치하는 경우 첫 번째 행이 삭제되기 때문에 첫 번째 행 이전의 행은 삭제되지 않습니다.
ed
편집기를 사용하십시오 :
printf '%s\n' 'g/pattern/ -1,. d' ,p Q | ed -s file
g/pattern/ -1,. d
그러면 파일 내용 에 명령이 적용됩니다 . 이 명령은 일치하는 각 줄을 검색한 pattern
다음 해당 줄과 그 앞의 줄을 삭제합니다.
최종 ,p
편집 Q
명령은 전체 파일을 인쇄하고 저장하지 않고 편집기를 종료합니다.
패턴이 두 개의 연속 행과 일치하는 경우 첫 번째 행 앞의 행을 삭제한 후 두 번째 행 앞의 행을 삭제합니다.
(마지막 문장은옳은글을 쓰다 보면 분명 그냥 쓰는 문장인 게 분명하다. )
grep
비표준이지만 일반적으로 사용되는 -B
옵션을 사용하여 삭제해야 하는 줄 번호를 제공 할 수도 있습니다 . 이 숫자는 sed
원시 데이터에서 실행되는 스크립트 로 변환될 수 있습니다 .
grep -n -B1 'pattern' file | sed 's/[:-].*/d/' | sed -f /dev/stdin file
grep
질문의 텍스트를 기반으로 명령이 출력됩니다.
2-line 2
3:pattern
...첫 번째 sed
명령은 이를 sed
편집 명령 으로 변환하고 2d
그 다음에는 3d
("2행과 3행 삭제")가 이어집니다. sed
파이프라인의 마지막 명령은 이 편집 스크립트를 가져와 원본 텍스트에 적용합니다.
이 변형은 먼저 삭제해야 할 모든 줄을 찾은 다음 삭제하는 2단계 접근 방식을 사용하기 때문에 패턴과 일치하는 연속 줄의 문제가 없습니다(텍스트를 처음 읽을 때 줄을 삭제하는 대신).
답변2
tac과 함께 awk를 사용하면 일치하는 패턴 앞의 행을 원하는 만큼 제거할 수 있습니다.
$ tac file | awk '/pattern/{c=2} !(c&&c--)' file | tac
line 2
line 1
삭제하려는 행 수(최대 일치하는 행까지)를 변경하세요. 예를 들어 숫자 97과 그 앞의 94개 행을 삭제 c=2
하세요 .c=5
$ seq 100 | tac | awk '/97/{c=95} !(c&&c--)' | tac
1
2
98
99
100
이제 awk 대신 sed를 사용해 보세요 :-).
바라보다인쇄를 위해 sed- 또는 awk-a-line-follow-a-matching-pattern을 사용하십시오.이것과 다른 관련 관용구에 대한 설명입니다.
답변3
노트:file
이 코드는 의 출력과 일치하는 각 행에 대해 중복된 행이나 하위 문자열이 없는 경우 에만 작동합니다 grep -B1 pattern file
.
예를 들어 file
다음 줄을 포함하는 경우:
line 1
line 2
line 2
pattern
line 1 line 2
line 3
그리고 내가 사용하는 출력은 grep -B1 pattern file | grep -v "$(cat)" file
여러분이 기대하는 것과 다를 것입니다.
line 1
line 3
이 문제를 해결하는 가장 좋은 방법은 다음을 사용하는 것입니다.코살로난다의 답변
해결책(위에서 설명한 것처럼 중복된 행이나 하위 문자열이 없는 경우에만 작동합니다)
이것은 bash
나에게 효과적입니다(더 좋은 방법이 있다고 생각합니다).
grep -B1 pattern file | grep -v "$(cat)" file
zsh
위 명령 에는 아무런 영향이 없습니다. 이유는 모르겠습니다. 하지만 다음을 사용할 수 있습니다.
grep -B1 pattern file | { val="$(cat)" ; grep -v "$val" file; }
폴리스티렌cat your_file | grep pattern
중복되므로 사용할 필요가 없습니다 . 당신은 사용해야합니다grep pattern your_file
답변4
pcregrep
Ultiline 모드를 사용할 수 있습니다 M
.
pcregrep -Mv '\n.*pattern'
첫 번째 행이 패턴과 일치하면 삭제되지 않습니다. 이 문제는 다음을 사용하여 해결할 수 있습니다.
pcregrep -Mv '(\n)?.*pattern'
( (...)
이 부분은 \n
분명히 필요한데 버전 8.39에서는 왜 작동하지 않는지 모르겠습니다 \n?.*pattern
. )[\n]?.*pattern