단어가 포함된 cmd
모든 *.cpp
및 파일 에 대해 실행하고 싶다고 가정해 보겠습니다.*.hpp
FOO
을 텐데발견하다파일이 사라져요. 할 수 있다는 걸 알아요.
find /path/to/dir -name '*.[hc]pp' -exec grep -l 'FOO' {} +
하지만 cmd
내가 할 수 있도록 처리를 확장하는 올바른 방법은 무엇입니까(예: 각 파일에 대해)?
-exec bash -c '...'
나는 내가 할 수 있고 쓸 수 있다는 것을 안다 ." 내용에 다음이 포함되어 FOO
있으면 cmd
파일에서 실행합니다 . "논리 ...
인데 대포를 쏘는 것 같은 느낌이 든다.
답변1
-exec … \;
또한 내부 명령이 종료 상태 0을 반환하는 한 테스트는 성공합니다. -exec … +
하나의 명령으로 많은 경로 이름을 처리할 수 있으며 항상 성공하므로 이는 유용한 테스트가 아닙니다.
grep -q
-exec … \;
일치하는 항목이 있으면(오류가 감지된 경우에도) 종료 상태 0을 반환하고 그렇지 않으면 1을 반환하므로 함께 잘 작동합니다 .
-exec grep … +
필요한 명령을 조건부로 실행하기 위해 다른 파일을 추가할 수 있도록 파일을 하나씩 테스트합니다 .-exec grep -q … \;
-exec
find /path/to/dir -name '*.[hc]pp' -exec grep -q 'FOO' {} \; -exec …
일반적으로 -exec … \;
테스트를 사용하면 거의 모든 것을 테스트할 수 있는 사용자 정의 테스트를 구축할 수 있습니다. 특히 sh -c
파이프, 조작할 수 있는 변수, 셸 조건 등을 사용하여 테스트를 실행할 수 있기 때문입니다. 조금:find -exec sh -c
사용해도 안전한 가요 ?).
답변2
이러한 유틸리티(및 ksh 스타일 프로세스 대체를 지원하는 셸)의 GNU 구현을 사용하면 다음을 수행할 수 있습니다.
xargs -r0a <(grep -rlZ --include='*.[hc]pp' FOO) cmd --
위에서 -r
(일명 --recursive
) 을 사용하면 작업을 grep
수행하고 (현재 버전에서는 해당 명령에 전달된 것처럼 동작함 ) NUL로 구분된 파일 경로 목록( ) 을 파이프하여 (일명 ) 에 전달된 경로를 파이프합니다 .find
grep
-type f
find
l
-Z
xargs
-a
--arg-file
계속 사용하고 싶다면 find
(예: 파일 이름 접미사보다 더 복잡한 파일 조건 적용) 다음을 수행할 수 있습니다.
xargs -r0a <(
find . -name '*.[hc]pp' -type f -exec grep -lZ FOO {} +
) cmd
( --
파일 경로가 ./
so not -
nor 로 시작하므로 여기서는 필요하지 않습니다 +
.)
실행은 find ... -exec grep -q FOO {} \; -exec cmd {} +
작동하지만 프로세스를 분기하고 실행하는 것을 의미합니다. 여기 에는 각 파일에 대한 공유 라이브러리를 로드하고 연결하는 작업이 포함됩니다. 이는 여기서 수행해야 하는 작업 (몇 KiB의 텍스트를 읽고 살펴보는 것) grep
보다 훨씬 더 비쌉니다 . , 따라서 성능이나 리소스 사용량이 문제라면 가능하면 피하는 것이 가장 좋습니다.grep
FOO
GNU System²를 사용하지 않지만 POSIX 표준 의 다음 버전을 find
지원 -print0
하고 지원하는 경우 다음을 사용하여 파일 경로를 보고할 수 있습니다 .xargs
-r
-0
perl
find . -name '*.[ch]pp' -type f -print0 |
xargs -r0 perl -0lne 'if (/FOO/} {print $ARGV; close ARGV}' |
xargs -r0 cmd
이는 stdin에서 읽지 않는다고 가정하지만 cmd
(여기서는 구현에 따라 xargs
/dev/null에서 열리거나 파이프의 읽기 끝이 perl
에서 상속되어 쓰기 중입니다 xargs
).
<(...)
1 rc와 유사한 쉘에 pdksh, zsh 및 bash를 기반으로 한 것 이외 의 ksh 구현을 포함합니다.<{...}
(...|psub)
fish
² 그러나 GNU는 grep
한때 BSD에서 사용되었으며(그리고 여전히 일부 BSD에서 사용됨) GNU에서 벗어난 일부 BSD는 해당 API를 복사했기 때문에 GNU가 아닌 구현이 GNU 가 아닌 구현 을 지원한다는 grep
점에 유의하세요. -표준 옵션; 때로는 OpenBSD , FreeBSD 또는 MacOS와 같은 긴 옵션과 동등한 옵션 만 있습니다 .grep
-Z
--null
-Z
답변3
globstar
먼저 Bash에서 이 옵션을 활성화하세요.
shopt -s globstar
이제 간단히 다음을 수행할 수 있습니다.
for x in /path/to/dir/**/*.[hc]pp; do
if grep -q 'FOO' "$x"; then
...
fi
fi
패턴 **
은 0개 이상의 경로 구성 요소와 일치합니다(디렉토리만 뒤에 오는 경우 /
).
따라서 패턴 /path/to/dir/foo.cpp
도 발견됩니다 /path/to/dir/deeply/nested/foo.cpp
.
답변4
xargs를 연결하는 흥미로운 사례:
find /path/to/dir -name '*.[hc]pp' -print0 | xargs -0 grep -lZ 'FOO' | xargs -0 ...
명령에 따라 -n 1
다음으로 전달해야 할 수도 있습니다.두번째xargs
각 파일에 대해 명령을 실행하기 위해 호출됩니다 .
이 find
명령은 일치하는 파일 이름의 0으로 구분된 이진 목록을 생성합니다. 첫 번째 xargs
명령은 모든 파일에서 일치하는 콘텐츠를 테스트하기 위해 최소 개수의 grep
명령을 연결하여 패턴과 일치하는 0으로 구분된 이진 파일 목록을 생성하고, 두 번째 xargs
명령은 실행됩니다 . 필요한 명령.