grep의 -A -B -C 스위치에 대한 대안이 있습니까 (앞뒤에 몇 줄 인쇄)?


10
grep -A 2 -B 3 

grep 문자열 다음에 2 행을 인쇄하고 3 행 전에 인쇄합니다.

grep -C 3

3 행 전과 3 행 인쇄

불행히도, grep내가 사용하는 것은 이러한 옵션을 지원하지 않습니다. 이를 시뮬레이션하기 위해 사용할 수있는 대체 명령이나 스크립트가 있습니까? 사용 sed/ awk/ perl/ 쉘 스크립트를?


+1 -C스위치 가 있다는 것을 몰랐습니다 .
Lazer

1
GNU의 grep을 설치하십시오. 보다 일반적으로 새로운 Sun 시스템이 여기에 도착했을 때 설정의 첫 번째 단계는 누군가가 호출 한 것 GNU > /usr/local입니다. GNU 프로그램은 매우 유용한 확장 기능을 많이 가지고 있으며, 임의의 제한을 피하도록 설계되었습니다 (그러나 크기와 성능이 크게 저하됩니다). 많은 독점 시스템에는 GNU 및 기타 도구와 함께 "비공식"패키지 리포지토리가 있습니다. "파트너"는 공급 업체가 관리하더라도 그들에 대해 말하지 않습니다.
vonbrand

답변:


6

적당히 못생긴 방법 중 하나는

grep -v pattern file >file.tmp; diff -c file.tmp file

또는 교체 -c-C NUM대한 NUM컨텍스트의 라인. 그러나 추가 출력을 생성합니다. ( diff지원하는 경우 -u/ -U NUM가 더 깨끗합니다.)

/ / diff가없는 경우 여전히 할 수있는 방법이 있지만 꽤 추한 것입니다. 다른 한편으로는, 심지어 지원하지 않는 시스템 에는 아마도 Perl이 없을 것입니다.-c-C-udiff-c


이것은 멋지다. 매력처럼 작동하지만 Windows 생성 파일에서 작동하도록 -bitw 옵션을 사용해야했습니다.
Prashant Bhate

stdin을 diff로 보내고 임시를 건너 뛸 수 있습니다.grep -v pattern file | diff -c - file
Cascabel

5

ACK는 단지 펄을 필요로하며, 포함 -A, -B-C그렙의 같은 그 일을 옵션. grep 대신에 Perl의 정규식 구문을 사용하며 검색 할 파일을 선택하는 방법이 상당히 다릅니다. -f옵션을 사용할 때 시도해 볼 수 있습니다 (실제로 아무것도 검색하지 않고 검색 할 파일을 인쇄합니다).

비 핵심 모듈이 필요없는 단일 스크립트 로 설치할 수 있습니다 . 그냥에 놓으 ~/bin그것의 디렉토리 (또는 다른 곳에서는 당신이 쓰기 액세스 권한이 사용자의 PATH에) 및 확인 chmod'D 실행.


그것의 생산 박스와 불행히도 나는 아무것도 설치하기에 충분한 특권을 가지고 있지 않으며, 위험을 감수 할 수는 없지만,이 팁 덕분에 그것을 설치하고 내 집의 노트북에서 시도 할 것입니다.
Prashant Bhate

@Prashant, 당신은 ack당신 자신의 사용을 위해 루트를 설치할 필요가 없습니다 .
CJM

그렇습니다. 그러나이 스크립트가 내 ~ / bin에 영원히있을 것이라는 확신이 있지만, 여전히 그곳에서 사용할 수는 없습니다.
Prashant Bhate

@Prashant : 왜 사용할 수 없습니까? 그것은 단지 펄 스크립트입니다.
intuited

1
PRODUCTION 상자에는 특별한 권한 승인이 필요합니다. 그리고 거기에 잘못이 내 머리에 온다;) 그리고 그만한 가치가 :)
Prashant Bhate

5

이 간단한 펄 스크립트는 grep -A어느 정도 모방

#!/usr/bin/perl

$pattern=shift; #patthern to search
$lines=shift; # number of lines to print

$n = 0;
while (<>) {
  $n = $lines if /$pattern/; # reset counting
  if ($n) { print; $n-- } # print if within
  $n = 0 if eof; # don't leak across file boundaries
}

스크립트를 읽고 사용할 수 있도록 사용법을 추가 할 수 있습니다.

USAGE:    $./grep-A.pl <pattern> <numLines> <filename> 

좋아, 어떤 버전의 perl을 실행해야합니까?
Prashant Bhate

나는 v5.10.1을 사용하는데 요즘 perl 5가 상당히 일반적이라고 생각합니다.
Vijay Anant

나중에 그것의 5.8.8 그리고 그것은 잘 작동하지만, 나는 -B 무엇을 수행 스크립트
Prashant Bhate

좋은. 그러나 나는 논쟁의 순서를 바꿀 것이다. grep-A 3 foo보다 자연스럽게 보입니다 grep-A foo 3. :-)
musiphil 2019

3

GNU grep 또는 Ack (Perl로 작성되고 많은 GNU grep 옵션 등을 이해함) 만 설치할 수 있습니다 .

표준 도구와 약간의 스크립팅을 고수하려면 GNU grep 과 옵션 의 동작을 에뮬레이트 하는 awk 스크립트가 있습니다. 최소한의 테스트.-A-B

#!/bin/sh
# grep-ac: a grep-like awk script
# Arguments: pattern = awk regexp to search for
#            before = number of lines to print before a match
#            after = number of lines to print after a match
{ "exec" "awk" "-f" "$0" "$@"; }
# The array h contains the history of lines that haven't been printed
# but are eligible for being "before" lines.
# The variable until contains the number of the last "after" line to print.
match($0, pattern) {   # the current line matches
    for (i in h) {
        print h[i];    # print each remaining before line
        delete h[i];   # delete each line as it's printed
    }
    until=NR+after;    # record the last after line to print
}
{
    if (NR<=until) print $0;    # from a match to its last after line: print
    else h[NR]=$0;              # after that: save in history
    delete h[NR-before];        # remove line too old to be a before line
}
END {exit !until}               # exit status: 0 if there was a match, else 1

로 실행 grep-ac -vpattern=PATTERN -vbefore=NBEFORE -vafter=NAFTERPATTERN(AN 검색 할 패턴 확장 정규 표현식 몇 가지와 AWK 추가 ),과 NBEFORENAFTER전에 각각 (0 디폴트)는 경기 후 인쇄 라인의 숫자입니다. 예:

<input_file grep-ac -vbefore=2 -vpattern='foo *bar'

배열에 데이터를 저장하는 모든 솔루션은 의문의 여지가 있습니다 ... 앞에서 언급했듯이 파일 크기는 상당히 커서 넘칠 수 있습니다. 또한이 시스템의 awk는 3000 바이트 이상의 파일 크기를 허용하지 않습니다.
Prashant Bhate

2
@Prashant : 귀하의 반대 의견을 이해하지 못합니다. 이 스크립트는 사전 라인이 될 수없는 라인을 삭제합니다. awk가 특수 목적 프로그램보다 오버 헤드가 높을 수도 있지만 (또한 고려중인 Perl보다 적음) 것을 제외하고는 요구 사항에 따라 본질적으로 필요한 것보다 많은 메모리를 사용하지 않습니다. 파일의 전체 크기는 전혀 관련이 없습니다.
Gilles 'SO- 악의를 멈춰라'

2
{ "exec" "awk" "-f" "$0" "$@"; }: shebang-line parsing의 한계를 극복하는 매우 멋진 방법입니다.
dubiousjim

2

서로 직접 일치하는 줄을 가질 때 발생하는 문제 때문에 -B를 에뮬레이트하는 것이 매우 까다로운 것으로 나타났습니다. 이것은 모든 종류의 단일 통과 파일 스캔을 사용하는 것을 거의 허용하지 않습니다.

나는 다음과 같은 근사치를 가지고 놀면서 이것을 깨달았습니다.

perl -pe 'if(/search_term/) {print foreach @A; print ">"; $B=4}; shift @A if push(@A, $_)>7; $_ = "" unless ($B-- > 0);' target_file

이것은 grep -A7 -B3과 마찬가지로 대략적으로 올바르게 작동하며 첫 번째 단락에 설명 된주의 사항이 있습니다.

이 문제에 대한 대안 (또한 단일 파일) 솔루션은 perl을 사용하여 sed에 명령 문자열을 공급하는 것입니다.

sed -n `perl -pe '$_=(/search_term/?sprintf("%d,%dp;", $.-3,$.+4):"")' file` file

꽤 긴 oneliner,하지만이 파일은 매우 커서이 경우 라인을 배열로 밀어 넣는 것은 나쁜 생각입니까?
Prashant Bhate

shift @A if push(@A,$_)>7;비트만을 최대 크기 (7) 주위의 배열을 유지한다. (-A 매개 변수입니다). 두 번째 옵션은 놀라 울 정도로 작은 파일을 유지합니다 (sed 외부 레이어없이 perl을 실행하여 생성 된 내용을 확인하십시오). 그러나 파일을 두 번 읽습니다.
user455

0

를 사용 sed하면 먼저 일치하는 줄의 줄 번호를 가져와 while루프 에서 주어진 줄 번호를 줄이거 나 늘린 다음 sed -n "n1,n2p"선행 ( n1) 및 후행 ( n2) 컨텍스트의 줄을 인쇄 하는 데 사용할 수 있습니다 ( seduser455에서 제안한 대안 과 유사 ). 많은 읽기 프로세스로 인해 성능이 저하 될 수 있습니다.

ed일치하는 줄의 이전 및 다음 줄을 직접 참조 할 수 있지만 지정된 줄 범위가 없으면 실패합니다. 예를 들어, 일치하는 줄은 줄 번호 2이지만 5 개의 사전 일치 줄을 인쇄해야합니다. 사용 ed이 것은 시작과 끝 (빈) 라인의 적절한 수를 추가 할 필요가있다. (거대한 파일 ed이 올바른 도구가 아닐 수 있습니다 : bfs-big file scanner 참조 ).

# sample code to match lines with number 5 plus previous & following line
# (using Bash)
printf '%s\n' {1..20} > num.txt

# sed
sed -n '/5/=' num.txt | while read num; do
   n1=$((num - 1))
   n2=$((num + 1))
   [[ $n1 -lt 1 ]] && n1=1
   sed -n "${n1},${n2}p" num.txt
   echo --
done | sed -e '${/^--$/d;}'

# ed
cat <<-'EOF' | ed -s num.txt | sed -e $'N;N;a\\\n--' | sed -e '${/^--$/d;}'
H
0i
beginning: added line one
.
$a
end: added line one
.
,g/5/km\
'm-1,'m+1p
q
EOF
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.