sed가있는 파일에서 모든 발생을 찾으십시오.


15

OPEN STEP 4.2 OS 사용 중 ... 현재 다음 sed명령을 사용하고 있습니다 .

sed -n '1,/141.299.99.1/p' TESTFILE | tail -3

이 명령은 ip가 141.299.99.1 인 파일에서 하나의 인스턴스를 찾은 다음 3 줄을 포함합니다. 단, IP의 모든 인스턴스와 3 줄을 찾기를 제외하고는 모두 좋습니다. 그리고 처음 만이 아닙니다.


1
제발 항상 당신의 OS를 포함한다. 솔루션은 종종 사용중인 운영 체제에 따라 다릅니다. 유닉스, 리눅스, BSD, OSX 등을 사용하고 있습니까? 어떤 버전?
terdon

좋은 점! Open Step 버전 4.2를 사용하는 것은 상당히 오래되었으며 포함 된 쉘에는 아래 답변에 언급 된 많은 기능이 포함되어 있지 않습니다.
Dale

호기심에서-OPEN STEP 4.2 시스템이란 무엇이며 오늘날 사용되는 시스템은 무엇입니까?
Thorbjørn Ravn Andersen

(그리고 Perl이 가능하다면 정말 좋은 일을 많이 할 수 있습니다)
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen 아마도 이것입니다 : en.wikipedia.org/wiki/OpenStep
Barmar

답변:


4

다음 grep -B3이 GNU sed 예제를 기반으로 sed moving window를 사용하여 에뮬레이션하려는 시도입니다 (그러나 POSIX 호환-@ StéphaneChazelas에 대한 승인).

sed -e '1h;2,4{;H;g;}' -e '1,3d' -e '/141\.299\.99\.1/P' -e '$!N;D' file

처음 두 표현식은 다중 라인 패턴 버퍼를 프라이밍하여 첫 번째 일치 이전에 선행 컨텍스트의 3 행 미만이있는 경우를 처리 할 수 ​​있도록합니다. 중간 (정규식 일치) 표현식은 원하는 일치 텍스트가 패턴 버퍼를 통해 리플 될 때까지 창의 맨 위에 줄을 인쇄합니다. 마지막 $!N;D은 입력이 끝날 때를 제외하고 창을 한 줄씩 스크롤합니다.


-eGNU 고유의 것이 아닙니다. POSIX / 휴대용이 되려면, 그 이후에는 아무것도 없어서 }필요합니다 ;.
Stéphane Chazelas

감사합니다 @ StéphaneChazelas-POSIX / 휴대용이 되려면 첫 번째 그룹을 다음과 같이 분할 / 수정해야 -e '1h;2,4{H;g;}' -e '1,3d'합니까? 테스트 할 GNU가 아닌 시스템 --posix이 없으며 GNU sed 스위치는 신경 쓰지 않는 것 같습니다.
스틸 드라이버

1
예, Linux에서는 sed전통적인 Unix sed의 후손 인 가보 툴을 사용하여 다른 구현을 테스트 할 수 있습니다 . POSIX / Unix 사양 sedpubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html에 있습니다.
Stéphane Chazelas

다음 중 하나에서 이벤트를 찾을 수 없습니다. N; D ': 이벤트를 찾을 수 없습니다. 어딘가에 구문이 없습니까? 감사!!
Dale

죄송합니다. 가장 최근의 편집 내용이 첫 번째 e 표현식 다음에 닫는 작은 따옴표를 생략했습니다. 지금 수정했습니다. 위의 표현으로 다시 시도해 주시겠습니까?
스틸 드라이버

10

grep 더 나은 일을 할 것입니다 :

grep -B 3 141.299.99.1 TESTFILE

-B 3수단은 각 경기 전에 세 줄을 인쇄합니다. --각 줄 그룹 사이에 인쇄 됩니다. 이를 비활성화하려면 사용하십시오 --no-group-separator.

-B옵션은 GNUgrep 및 대부분의 BSD 버전에서도 지원됩니다 ( OSX , FreeBSD , OpenBSD , NetBSD )에서도 지원되지만 기술적으로 표준 옵션은 아닙니다.


1
마이클 호머-감사합니다. -B 옵션이 없습니다. 다른 아이디어가 있습니까?
Dale

@Dale GNU grep을 설치할 수 있습니까? 옵션이 제공됩니다.
Barmar

9

으로 sed당신은 슬라이딩 윈도우를 할 수 있습니다.

sed '1N;$!N;/141.299.99.1/P;D'

그렇습니다. 그러나 인용 할 때조차도bash 확장하는 미친 행동 ! ! 명령 기록에서 명령 문자열로 들어가면 약간 미친 듯이 보일 수 있습니다. set +H;이 경우 명령 앞에 접두사를 붙 입니다. 다음을 다시 사용하려면 (??? 왜하지만)set -H나중에.

물론, 당신 사용 bash하고있는 경우에만 적용됩니다 . 난 꽤 특정 작업중인 csh- (누구의 미친 행동 쉘 될 일이있는 bashC 쉘은 그것을했다 극단의 역사 확장과 모방을하지만, 아마) . 그래서 아마 a는 \!작동합니다. 나는 희망.

그것은 모든 휴대용 코드입니다 : POSIX는 설명 따라서 세 개의 연산자 : (I 만이 설명을 확인했다고 지적 그것의 가치가로 2001 년 초와 같은 존재하지만)

[2addr]N 추가 된 재료를 원래 재료와 분리하기 위해 \n내장 된 \newline을 사용하여 다음 입력 라인 (종료 ewline을 줄임)을 패턴 공간에 추가합니다. 현재 줄 번호가 변경됩니다.

[2addr]P 첫 번째 \newline 까지의 패턴 공간 을 표준 출력에 씁니다.

[2addr]D 첫 번째 \newline을 통해 패턴 공간의 초기 세그먼트를 삭제하고 다음주기를 시작하십시오.

따라서 첫 번째 줄에서 패턴 공간에 추가 줄을 추가하면 다음과 같습니다.

^line 1s contents\nline 2s contents$

그런 다음 첫 번째 줄과 그 이후의 모든 줄에-마지막 줄을 제외하고- 패턴 공간에 다른 줄을 합니다. 따라서 다음과 같이 보입니다.

^line 1\nline 2\nline 3$

IP 주소가 발견 P되면 첫 번째 줄 바꿈까지 찢으십시오. 모든 사이클이 끝나면D 은 똑같이 뛰어 들고 남아있는 것을 다시 시작합니다. 다음주기는 다음과 같습니다.

^line 2\nline 3\nline 4$

...등등. 당신의 IP가 그 세 가지 중 하나에서 발견되면, 가장 오래된 것-매번 인쇄됩니다. 그래서 당신은 항상 세 줄의 앞.

다음은 간단한 예입니다. 0으로 끝나는 모든 숫자에 대해 3 줄 버퍼가 인쇄됩니다.

seq 10 52 | sed '1N;$!N;/0\(\n\|$\)/P;D'

10
18
19
20
28
29
30
38
39
40
48
49
50

그 중 하나를 번갈아 가야했기 때문에 그게 당신의 경우보다 조금 더 복잡합니다. 0\n 줄 바꿈 또는0$문제와 더 유사하게 패턴 공간 끝 하지만 앵커가 필요하다는 점에서 미묘하게 다릅니다. 패턴 공간이 끊임없이 이동합니다.

나는 10과 52의 홀수 경우를 사용하여 앵커가 유연하고 출력도 마찬가지라는 것을 보여주었습니다. 완전히 이식 가능하게, 대신 알고리즘을 계산하여 동일한 결과를 얻을 수 있습니다.

seq 10 52 | sed '1N;$!N;/[90]\n/P;D'

내 창을 제한하면서 검색 범위를 넓히십시오-0에서 9 및 0 및 3 줄에서 2 줄로.

어쨌든, 당신은 아이디어를 얻습니다.


모든 노력에 감사드립니다. 죄송합니다. 검색 할 파일 이름을 어디에 넣을까요?
Dale

@ 데일-내 나쁜. sed '...' $filename. 그건 그렇고-나는 당신의 검색 문자열에서 마침표를 남겼지 만 실제로는 패턴의 마침표가 아닙니다-그것들은 단일 문자를 나타냅니다. 당신은 아마 어떻게해야 oct\.oct\.oct\.oct그들이 그렇게 그들을 탈출 에만 기간을 일치합니다.
mikeserv

나는 그것과 다른 <> 기호로 고양이를 찾으려고 여기에 다른 솔루션으로 얻을 수있는 이벤트를 찾을 수 없으므로 내 OS가 이러한 솔루션과 호환되지 않는지 궁금합니다.
Dale

이제-> N; /141.299.99.1/P; D '의 결과 : 이벤트를 찾을 수 없습니다.
Dale

@ 데일-업데이트를 참조하십시오. 도움이 될 것입니다.
mikeserv

4

에 대한 옵션 이 없다고 언급 했으므로 Perl (예 :)을 사용하여 4 줄의 창을 슬라이딩 할 수 있습니다.-Bgrep

perl -ne '
    push @window,$_;
    shift @window if @window > 4;
    print @window if /141\.299\.99\.1/
' your_file

Ramesh의 답변은와 비슷한 작업을 수행 awk합니다.


내 Perl 버전이이를 지원하는지 확실하지 않지만 시도해 볼 것입니다. 내 질문에 대답하는 데 시간을내어 주셔서 대단히 감사합니다-매우 감사합니다!
Dale

@Dale 천만에요. 이 코드가 최첨단 Perl 기능을 사용하는지 의심합니다.
Joseph R.

4

가능한 경우 pcregrep을 사용할 수 있습니다 .

pcregrep -M '.*\n.*\n.*\n141.299.99.1' file

PCREGREP가 있는지 확인 중입니다. 나는 명령의 소형화를 좋아한다. 시간과 노력에 감사드립니다. 감사합니다!!!
Dale

4

쉘 자체에서 다른 grep이 아닌 응답과 동일한 기본 접근 방식을 구현할 수 있습니다 (이는 비교적 최근의 쉘을 지원한다고 가정합니다 =~).

while IFS= read -r line; do 
    [[ $line =~ 141.299.99.1 ]] && printf "%s\n%s\n%s\n%s\n" $a $b $c $line;
    a=$b; b=$c; c=$line; 
done < file 

또는 전체 파일을 배열에 넣을 수 있습니다.

perl -e '@F=<>; 
        for($i=0;$i<=$#F;$i++){
          print $F[$i-3],$F[$i-2],$F[$i-1],$F[$i] if $F[$i]=~/141.299.99.1/
        }' file 

내 쉘은 매우 오래되었습니다-Steve Jobs Open Step. 그래도 좋은 생각이고 시간 내 주셔서 감사합니다 !!! 데일
데일

@Dale the perl 접근법은 거의 모든 곳에서 작동합니다. 귀하에게 적합한 것을 제안 할 수있는 방식으로 운영 체제를 알려주십시오 (질문에 추가하십시오).
terdon

Perl을 복사하여 메모장에 넣고 한 줄에 넣으면 작동합니다! 질문-원하는 경우 일치 패턴 앞에 10 줄을 말하면 3에서 10을 어디에서 바꿀 수 있습니까? 감사!
Dale

더 많은 $ F [$ iX] 문을 추가하여 줄을 다시 추가 할 수 있습니다. 감사!
Dale

4

시스템이 grep컨텍스트를 지원하지 않으면 ack-grep을 대신 시도 할 수 있습니다 .

ack -B 3 141.299.99.1 file

ack 프로그래머에게 최적화 된 grep과 같은 도구입니다.


나는 명령의 소형화를 좋아하지만 내 시스템은 매뉴얼 페이지를 볼 때 ack을 지원하지 않습니다. 좋은 생각과 시간 내 주셔서 감사합니다 !!! 데일
데일

@ 데일 : 놀랍습니다! 당신의 OS는 무엇입니까? 가지고 있다면 perl사용할 수 있습니다 ack.
cuonglm

2
awk '/141.299.99.1/{for(i=1;i<=x;)print a[i++];print} {for(i=1;i<x;i++)
     a[i]=a[i+1];a[x]=$0;}'  x=3 filename

awk솔루션 에서는 현재 패턴 앞에 항상 3 줄을 포함하는 배열이 사용됩니다. 따라서, 패턴이 일치하면, 현재 패턴과 함께 배열 내용이 인쇄된다.

테스팅

-bash-3.2$ cat filename
10.0.0.1
10.0.0.2
10.0.0.3
10.0.0.4
141.299.99.1
10.0.0.5
10.0.0.6
10.0.0.7
10.0.0.8
10.0.0.9
10.0.0.10
141.299.99.1
10.0.0.11
10.0.0.12
10.0.0.13
10.0.0.14
10.0.0.15
10.0.0.16
141.299.99.1
10.0.0.17
10.0.0.18
10.0.0.19

명령을 실행하면 출력은 다음과 같습니다.

10.0.0.2
10.0.0.3
10.0.0.4
141.299.99.1
10.0.0.8
10.0.0.9
10.0.0.10
141.299.99.1
10.0.0.14
10.0.0.15
10.0.0.16
141.299.99.1

매우 상세합니다-대단히 감사합니다. 시도해 볼게요. 시간 내 주셔서 감사합니다 !! 데일
데일

테스트 파일이 있고 솔루션이 작동합니다! 문제는 큰 프로덕션 파일에서 실행할 때 너무 긴 레코드 번호와 함께 돌아와서 출력이 명령으로 작동하지 않는 것입니다. 이 페이지 상단의 원래 명령은 작동하지만 하나의 인스턴스 만 찾습니다. 도와 주셔서 감사합니다. 원래 명령으로 둘 이상의 무질서를 찾도록 할 수있는 일이 있습니까?
Dale

1

이들의 대부분에서, /141.299.99.1/도 (예)를 일치 141a299q99+1또는 141029969951때문에. 정규식에서 모든 문자를 나타낼 수 입니다.

사용은 /141[.]299[.]99[.]1/안전합니다, 당신은 반드시 일치하지 않을 시작 부분에 추가 컨텍스트를 추가하기 위해 전체 정규 표현식의 끝 수 3141., .12, .104, 등


1
이것은 좋은 지적입니다. 또한 제가 고려한 것이기도합니다. 그래도, 나는 asker가 제공 한 문자열을 알려진 워킹 매치로 사용했고 기회가있을 때 그에게 개인적으로 알 렸습니다. 어쨌든 - 모든 - 이들의 steeldriver의 대답은 처음부터 문자 일치를 인용했다.
mikeserv
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.