“Foo”가 발생하는 모든 CPP 파일에 대해 전체 트리를 검색하려고한다고 가정하십시오. 나는 할 수있다 :
find . -name "*.cpp" | xargs grep "Foo"
이제 다른 문자열, 예를 들어 “Bar”가 이전 결과의 3 줄 내에 나타나지 않는 인스턴스 만 나열하려고한다고 가정하십시오 .
따라서 두 개의 파일이 주어졌습니다.
a.cpp
1 Foo
2 qwerty
3 qwerty
b.cpp
1 Foo
2 Bar
3 qwerty
a.cpp의 “Foo”가 있지만 b.cpp의 “Foo”가없는 간단한 검색을 구성하고 싶습니다.
상당히 간단한 방법으로 이것을 달성 할 수있는 방법이 있습니까?
답변
로 pcregrep
:
pcregrep --include='\.cpp$' -rnM 'Foo(?!(?:.*\n){0,2}.*Bar)' .
이 키는 -M
고유 한 옵션에 있으며 pcregrep
여러 줄을 일치시키는 데 사용됩니다 ( pcregrep
RE를 걸을 때 필요에 따라 입력 파일에서 더 많은 데이터를 가져옵니다).
(?!...)
perl / PCRE 네거티브 미리보기 RE 연산자입니다. Foo(?!...)
일치하는 Foo
만큼 ...
다음과 일치하지 않습니다.
...
인 (?:.*\n){0,2}.*Bar
( .
포함하는 행 하였다 0-2 선에서이고, 개행 문자에 일치하지 않음) Bar
.
답변
@StephaneChazelas가 제안한pcregrep
대로 사용하면 됩니다 .
이것은 작동해야합니다 :
$ find . -name "*.cpp" |
while IFS= read -r file; do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
아이디어는 grep의 -A
스위치 를 사용 하여 일치하는 줄과 N 다음 줄을 출력하는 것입니다. 그런 다음 a를 통해 결과를 전달하고 grep Bar
일치하지 않으면 (종료> 0) 파일 이름을 에코합니다.
빈 파일 이름 (공백, 줄 바꿈 또는 기타 이상한 문자가 없음)을 알고있는 경우 다음과 같이 단순화 할 수 있습니다.
$ for file in $(find . -name "*.cpp"); do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
예를 들면 다음과 같습니다.
terdon@oregano foo $ cat a.cpp
1 Foo
2 qwerty
3 qwerty
terdon@oregano foo $ cat b.cpp
1 Foo
2 Bar
3 qwerty
terdon@oregano foo $ cat c.cpp
1 Foo
2 qwerty
3 qwerty
4 qwerty
5. Bar
terdon@oregano foo $ for file in $(find . -name "*.cpp"); do grep -A 3 Foo "$file" | grep -q Bar || echo "$file"; done
./c.cpp
./a.cpp
참고 c.cpp
포함에도 불구하고 반환되는 Bar
행이 함께 있기 때문에 Bar
3 개 이상의 행 다음입니다 Foo
. 전달 된 값을 변경하여 검색하려는 행 수를 제어합니다 -A
.
$ for file in $(find . -name "*.cpp"); do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
./a.cpp
다음은 더 짧은 것입니다 (을 사용한다고 가정 bash
).
$ shopt -s globstar
$ for file in **/*cpp; do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
중대한
주석에서 Stephane Chazelas가 지적했듯이 위의 솔루션은 전혀 포함되지 않은 파일도 인쇄합니다 Foo
. 이것은 이것을 피합니다 :
for file in **/*cpp; do
grep -qm 1 Foo "$file" &&
(grep -A 3 Foo "$file" | grep -q Bar || echo "$file");
done
답변
테스트를 거치지 않았습니다.
find . -name "*.cpp" | xargs awk '/foo/{t=$0;c=10}/bar/{c=0;t=""}c{c--}t&&!c{print t;t=""}END&&t{print t}'
그런 것.