sed (또는 awk)로 패턴 위의 줄 범위 삭제


28

패턴이있는 줄과 그 banana뒤에 2 줄을 제거하는 다음 코드가 있습니다.

sed '/banana/I,+2 d' file

여태까지는 그런대로 잘됐다! 그러나 전에 2 줄을 제거해야하지만 banana“빼기 부호”또는 무엇이든 ( grep -v -B2 banana file해야 할 일과 비슷 하지만) 할 수는 없습니다.

teresaejunior@localhost ~ > LC_ALL=C sed '-2,/banana/I d' file
sed: invalid option -- '2'
teresaejunior@localhost ~ > LC_ALL=C sed '/banana/I,-2 d' file
sed: -e expression #1, char 16: unexpected `,'
teresaejunior@localhost ~ > LC_ALL=C sed '/banana/I,2- d' file
sed: -e expression #1, char 17: unknown command: `-'

1
가장 쉬운 방법은 모든 데이터를 배열에로드하고 원하지 않는 행을 건너 뛰고 남아있는 내용을 출력하는 것 awk '{l[m=NR]=$0}/banana/{for(i=NR-2;i<=NR;i++)delete l[i]}END{for(i=1;i<=m;i++)if(i in l)print l[i]}'입니다. 이것은 효율적이지 않으므로 솔루션이 아니라 힌트 일뿐입니다.
manatwork

6
그냥하세요 tac file | sed ... | tac. : P
angus

@angus 나는 그것에 대해 생각하지 않았다;)
Teresa e Junior

1
당신은 할 수 있었다 sed '/banana/,+2d' file 그 것 또한 일
Akaks

1
awk를 사용할 수 있다면 매우 간단합니다. awk 'tolower($0)~/bandana/{print prev[!idx];print prev[idx]} {idx=!idx;prev[idx]=$0}' filein 이것은 주석이며 답변이 아니기 때문에 (이미 다른 답변이 있기 때문에) 너무 자세하게 설명하지는 않지만 그 요점은 항상 이전 [0] 이전 [1]에서 앞의 두 기록은 "신선한"하는 반복에 있지만 항상에 따라 prev[idx]인쇄 할 때, 그래서, 당신은에 인쇄 !idx다음 idx순서. 어쨌든 idx현재 레코드를 번갈아 가며 에 넣습니다 prev[idx].
Luv2code

답변:


22

Sed는 역 추적하지 않습니다. 일단 라인이 처리되면 완료됩니다. 따라서 접목하기 쉬운 "줄 찾기 및 다음 N 줄 인쇄"와 달리 "줄 찾기 및 이전 N 줄 인쇄"는 그대로 작동하지 않습니다.

파일이 너무 길지 않은 경우 GNU 확장에 문제가 없어 보이기 때문에 tac파일 줄을 반대로 바꿀 수 있습니다 .

tac | sed '/banana/I,+2 d' | tac

또 다른 공격 각도는 awk와 같은 도구에서 슬라이딩 윈도우를 유지하는 것입니다. 에서 적응 거기 grep와의 -A -B -C (를) 대체 할 수있는 다른 것은 (전후 몇 줄을 인쇄) 스위치? (경고 : 최소 테스트) :

#!/bin/sh
{ "exec" "awk" "-f" "$0" "$@"; } # -*-awk-*-
# The array h contains the history of lines that are eligible for being "before" lines.
# The variable skip contains the number of lines to skip.
skip { --skip }
match($0, pattern) { skip = before + after }
NR > before && !skip { print NR h[NR-before] }
{ delete h[NR-before]; h[NR] = $0 }
END { if (!skip) {for (i=NR-before+1; i<=NR; i++) print h[i]} }

용법: /path/to/script -v pattern='banana' -v before=2


2
sed슬라이딩 윈도우도 할 수 있지만 결과 스크립트는 일반적으로 읽을 수 없으므로 쉽게 사용할 수 있습니다 awk.
jw013

@Gilles .. awk스크립트가 옳지 않습니다. 빈 줄을 인쇄하고 마지막 줄을 놓칩니다. 이것은 그것을 고치는 것처럼 보이지만 이상적이거나 적절하지 않을 수도 있습니다 : if (NR-before in h) { print...; delete...; }... 및 END섹션 : for (i in h) print h[i]... 또한 awk 스크립트는 일치하는 줄을 인쇄하지만 tac/sec버전은 그렇지 않습니다. 그러나 질문은 이것에 약간 모호합니다 .. 링크를 제공 한 "원래"awk 스크립트는 잘 작동합니다. 좋아합니다 ... 위의 'mod'가 인쇄에 어떤 영향을 미치는지 잘 모르겠습니다. line ...
Peter.O

@ Peter.O 감사합니다. awk 스크립트가 더 좋아질 것입니다. 그리고 6-8 년이 채 걸리지 않았습니다!
Gilles 'SO- 악의를 그만두십시오

19

ex 또는 vim -e를 사용하면 매우 쉽습니다.

    vim -e - $file <<@@@
g/banana/.-2,.d
wq
@@@

현재 행 -2에서 현재 행까지의 바나나를 포함하는 모든 행에 대해 다음과 같이 표현합니다.

멋진 점은 범위에 뒤로 및 앞으로 검색을 포함 할 수 있다는 것입니다. 예를 들어 사과를 포함하는 줄로 시작하고 주황색을 포함하고 바나나가있는 줄로 끝나는 파일의 모든 섹션을 삭제합니다.

    vim -e - $file <<@@@
g/banana/?apple?,/orange/d
wq
@@@

7

"슬라이딩 창"사용 perl:

perl -ne 'push @lines, $_;
          splice @lines, 0, 3 if /banana/;
          print shift @lines if @lines > 2
          }{ print @lines;'

6

이 작업은 다음과 sed같이 간단하게 수행 할 수 있습니다 .

printf %s\\n    1 2 3 4match 5match 6 \
                7match 8 9 10 11match |
sed -e'1N;$!N;/\n.*match/!P;D'

왜 다른 사람이 다른 말을하는지 모르겠지만 이전 줄을 인쇄 sed 하려면 내장 된 Print 프리미티브 \n에 패턴 공간 의 첫 번째 ewline 문자 까지만 씁니다 . 보완적인 Delete 프리미티브는 남아있는 것을 스크립트를 재귀 적으로 재활용하기 전에 동일한 패턴 공간 세그먼트를 제거합니다. 그리고 반올림하기 위해 N삽입 된 \newline 문자 다음에 패턴 공간에 ext 입력 행을 추가하는 기본 요소가 있습니다.

한 줄만 sed있으면됩니다. match정규 표현식이 무엇이든 대체 하고 황금색입니다. 매우 빠른 솔루션 이어야합니다 .

이 올바르게 계산됩니다 것을 유의하십시오 match즉시 다른 앞의 match앞의 두 라인에 대한 조용한 출력 모두로를 트리거 하고 아니라 인쇄를 조용히 :


1
7match
8
11match

임의의 수의 라인에서 작동 하려면 리드를 얻는 것만 필요합니다.

그래서:

    printf %s\\n     1 2 3 4 5 6 7match     \
                     8match 9match 10match  \
                     11match 12 13 14 15 16 \
                     17 18 19 20match       |
    sed -e:b -e'$!{N;2,5bb' -e\} -e'/\n.*match/!P;D'

1
11match
12
13
14
20match

... 일치하는 5 줄을 삭제합니다.


1

사용 man 1 ed:

str='
1
2
3
banana
4
5
6
banana
8
9
10
'

# using Bash
cat <<-'EOF' | ed -s <(echo "$str")  | sed -e '1{/^$/d;}' -e '2{/^$/d;}'
H
0i


.
,g/banana/km\
'm-2,'md
,p
q
EOF
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.