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

grep -A 2 -B 3 

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

grep -C 3

3 행 전과 3 행 인쇄

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



답변

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

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


답변

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

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


답변

이 간단한 펄 스크립트는 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> 


답변

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'


답변

서로 직접 일치하는 줄을 가질 때 발생하는 문제 때문에 -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


답변

를 사용 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


답변