grep 컨텍스트를 줄에서 N 자로 제한


31

줄 길이가 수천자를 초과하는 일부 JSON 파일을 grep해야합니다. grep이 일치하는 왼쪽과 오른쪽에 최대 N자를 표시하도록 제한하려면 어떻게해야합니까? grep 이외의 도구는 일반적인 Linux 패키지에서 사용할 수있는 한 괜찮습니다.

가상 그렙 스위치 Ф에 대한 출력 예입니다 .

$ grep -r foo *
hello.txt: Once upon a time a big foo came out of the woods.

$ grep -Ф 10 -r foo *
hello.txt: ime a big foo came of t



3
중복되지 않습니다. 이것은 약 ± 문자이지만 권장되는 대안은 약 ± 라인입니다. ( 그러나 stackoverflow에 대한 언급 은 좋습니다.)
roaima

답변:


22

GNU로 grep:

N=10; grep -roP ".{0,$N}foo.{0,$N}" .

설명:

  • -o => 일치하는 내용 만 인쇄
  • -P => Perl 스타일 정규식 사용
  • 정규 표현식은 0을 $N문자 와 일치 시키고 foo그 뒤에 0을 문자 와 일치 $N시킵니다.

GNU가 없다면 grep:

find . -type f -exec \
    perl -nle '
        BEGIN{$N=10}
        print if s/^.*?(.{0,$N}foo.{0,$N}).*?$/$ARGV:$1/
    ' {} \;

설명:

우리는 더 이상 grepGNU에 의존 할 수 없으므로 파일을 재귀 적으로 검색하는 grep데 사용 find합니다 ( -rGNU 의 동작 grep). 발견 된 각 파일에 대해 Perl 스 니펫을 실행합니다.

펄 스위치 :

  • -n 파일을 한 줄씩 읽으십시오
  • -l 각 줄 끝에서 줄 바꿈을 제거하고 인쇄 할 때 다시 넣으십시오.
  • -e 다음 문자열을 코드로 취급

Perl 스 니펫은 기본적으로와 동일한 작업을 수행 grep합니다. 변수 $N를 원하는 컨텍스트 문자 수로 설정하여 시작합니다 . BEGIN{}수단이 모든 파일의 모든 라인 한번도 실행을 시작할 때 한 번만 실행됩니다.

각 행에 대해 실행 된 명령문은 정규식 대체가 작동하는 경우 행을 인쇄하는 것입니다.

정규식 :

  • 오래된 것은 유유히 일치 1 라인의 시작에 ( ^.*?) 다음 .{0,$N}같이 grep다음, 경우 foo다른 다음 .{0,$N}마지막 행의 마지막까지 느리게 오래된 일을 일치 ( .*?$).
  • 우리는 이것을로 대체합니다 $ARGV:$1. $ARGV읽고있는 현재 파일의 이름을 보유하는 마법 변수입니다. $1Parens가 일치하는 것입니다.이 경우의 컨텍스트입니다.
  • 욕심 많은 경기는 일치 foo하지 않고 모든 문자를 먹기 때문에 (두 번 일치 할 수 있기 때문에) 양쪽 끝에 게으른 경기가 필요합니다 .{0,$N}.

(1) 이 전체 일치 실패하지 않는 한이다, 아무것도 일치되지 선호합니다. 한마디로 가능한 적은 문자를 일치시킵니다.


아주 좋습니다 감사 해요. 이것은 검색된 텍스트뿐만 아니라 전체 출력을 강조 표시하는 단점이 있지만 | grep foo끝에 추가 하여 해결할 수 있습니다 (그러나 프로세스에서 파일 이름 강조 표시를 잃어 버림).
dotancohen

1
@dotancohen 나는 당신이 그들 모두를 이길 수 없다고 생각합니다 :)
Joseph R.

GNU grep에서 환경 변수를 통해 적용된 플래그를 기반으로 색상 / 응용 프로그램을 지정할 수 있습니다. 어쩌면 당신도 모두를 이길 수 있습니다 (약속은 없습니다-이 경우에는 잘 작동하지 않을 수도 있음). 하지만 개인적으로 여기 관련성을 보지 못합니다 ... 어쨌든 ... 계속 재생하십시오.
mikeserv

좋은 대답입니다. 참고로, zsh예제와 같이 N = 10을 전달하여 작동시키지 못했습니다. 그러나 export N=10명령을 실행하기 전에 작동합니다 . zsh와 함께 작동하도록 예제를 조정하는 방법에 대한 아이디어가 있습니까?
Gabe Kopley

또는perl -lne 'print "$ARGV: $_" for /.{0,10}foo.{0,10}/g'
Stéphane Chazelas

19

이것을 사용하십시오 :

grep -r -E -o ".{0,10}wantedText.{0,10}" *

-E 는 확장 정규식을 사용하고 싶다고 말합니다.

-o 는 일치하는 내용 만 인쇄하고 싶다고 알려줍니다.

-r grep이 폴더에서 재귀 적으로 결과를 찾고 있습니다.

정규식 :

{0,10} , 인쇄하려는 임의의 문자 수

. 임의의 문자를 나타냅니다 (문자 자체는 중요하지 않고 숫자 만 표시됨)

편집 : 아, 요셉은 내가하는 것과 거의 같은 해결책을 추천한다는 것을 알았습니다.


고맙습니다. 본질적으로 동일한 솔루션이지만 사람이 독립적으로 추천 할 때 이것이 가장 좋은 방법이라는 확신이 있습니다.
dotancohen

천만에요. 유닉스 커뮤니티는 단순히 협력해야합니다. 그것이 우리의 모습입니다 :-)
Eenoku

2
그것들은 비슷하지만 받아 들인 대답은 나에게 효과가 없었지만 (여전히 긴 줄이 생겼습니다), 그러나 하나는 그랬습니다. N = 10 인 트릭은 bash 쉘에서 작동하지 않습니다.
meesern

cygwin 에서 -E보다 훨씬 빠릅니다 -P.
Bob Stein

2

출처 : http://www.topbug.net/blog/2016/08/18/truncate-long-matching-lines-of-grep-a-solution-that-preserves-color/https : // stackoverflow. com / a / 39029954 / 1150462

제안 된 접근 방식 ".{0,10}<original pattern>.{0,10}"은 강조 색상이 종종 엉망이되는 것을 제외하고는 완벽하게 좋습니다. 비슷한 출력으로 스크립트를 만들었지 만 색상도 유지됩니다.

#!/bin/bash

# Usage:
#   grepl PATTERN [FILE]

# how many characters around the searching keyword should be shown?
context_length=10

# What is the length of the control character for the color before and after the matching string?
# This is mostly determined by the environmental variable GREP_COLORS.
control_length_before=$(($(echo a | grep --color=always a | cut -d a -f '1' | wc -c)-1))
control_length_after=$(($(echo a | grep --color=always a | cut -d a -f '2' | wc -c)-1))

grep -E --color=always "$1" $2 | grep --color=none -oE ".{0,$(($control_length_before + $context_length))}$1.{0,$(($control_length_after + $context_length))}"

스크립트가 저장됩니다 가정 grepl한 후, grepl pattern file_with_long_lines일치하는 행을 표시하지만 일치하는 문자열 약 10 문자로한다.


0

에 표준 출력을 배관 cut-b플래그; grep의 출력을 한 줄에 1-400 바이트로만 지시 할 수 있습니다.

grep "foobar" * | cut -b 1-400
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.