파일이 몇 개 있고 문자열은 포함하지만 다른 문자열은 포함하지 않는 파일을 찾고 싶다고 가정해 보겠습니다.
grep은 라인 기반이므로 이와 같은 조건은 grep -q printf file && grep -vq '#include <stdio.h>' file
작동하지 않습니다.
어떻게 해야 하나요?
(저는 Debian을 사용하므로 도구의 GNU 버전에 대한 답변이 적합합니다.)
답변1
grep -vl
패턴과 일치하는 행이 하나 이상 있는 파일 이름을 보고합니다. 여기서는 패턴과 일치하는 줄이 없는 파일을 원합니다. GNU grep
(Debian에 있음)에는 다음 -L
옵션이 있습니다.
grep -rlZ printf . | xargs -r0 grep -FL '#include <stdio.h>'
POSIX의 경우 grep
다음을 무효화할 수 있습니다 grep -q
.
find . -type f -exec grep -q printf {} \; \
! -exec grep -Fq '#include <stdio.h>' {} \; \
-print
grep
각 일반 파일에서 하나 또는 두 개의 인스턴스를 실행한다는 의미이므로 효율성이 훨씬 떨어집니다 .
답변2
스크립팅 대신 조합 find
하여 사용하세요 . bash -c
파일 경로를 가져와 file
변수에 저장하고 추가로 다른 명령에 전달합니다. 먼저 grep -q
원하는 단어/패턴이 있는지 확인합니다. 종료 상태를 사용하여 &&
두 번째 상태로 전달합니다 grep -q
. 명령이 일치하는 항목을 찾지 못하면 문자열을 찾을 수 없다는 의미이므로 종료 상태를 사용하여 이를 echo
via ||
연산자에 전달합니다.
아래 예에서는 단어 만 file2.txt
포함되고 abra
포함되지 않습니다 .cadabra
$ find -type f -exec bash -c 'file="$@";grep -q "abra" "$file" && grep -q "cadabra" "$file" || echo "$file" ' sh "{}" >
./file2.txt
$ ls
file1.txt file2.txt file 3.txt
$ cat file1.txt
abra cadabra
$ cat file2.txt
abra
$ cat file\ 3.txt
abra cadabra
답변3
이것은 매우 간단합니다.
for fname in ./*.c; do
if grep -q -F "printf" "$fname" && ! grep -q -F "#include <stdio.h>" "$fname"; then
printf 'File "%s" needs to include stdio.h\n' "$fname"
fi
done
그러면 현재 디렉터리의 모든 C 소스 파일을 살펴보고 헤더를 사용 printf()
하지만 포함하지 않는 모든 파일을 보고합니다 stdio.h
.
그러나 헤더가 간접적으로 포함될 수 있으므로 오탐을 방지하려면할 수 있다코드를 C 전처리기에 전달하고 전처리된 출력에서 헤더를 찾습니다(이것은 gcc
및 에서 작동하는 것 같습니다 clang
).
for fname in ./*.c; do
if grep -q -F "printf" "$fname" && cc -E "$fname" | ! grep -q "^#.*stdio\.h\""; then
printf 'File "%s" needs to include stdio.h\n' "$fname"
fi
done
답변4
요구 사항을 올바르게 읽으면 모든 파일 일치에서 $PAT_INCL
파일 일치를 뺀 값이 필요합니다 $PAT_EXCL
.
개념적으로 이는 단지 집합 빼기일 뿐입니다. Unix에는 집합 작업을 위한 아주 좋은 표준 유틸리티가 없지만 comm
사용할 수 있습니다.
comm -23 <(grep --files-with-match "$PAT_INCL" * | sort) \
<(grep --files-with-match "$PATH_EXCL" * | sort)
두 번째 grep에서 일치하는 파일만 찾으면 효율성이 향상될 수 있습니다.
# Assuming filenames without whitespace
grep --files-with-match "$PAT_INCL" * | sort > incl_files
grep --files-with-match "$PAT_EXCL" $(cat incl_files) | sort > excl_files
comm -23 incl_files excl_files