대규모 프로젝트의 소스코드를 통해 C 함수의 프로토타입을 읽어보고 싶습니다.
나는 함수 이름과 그 반환 유형을 알고 있으며, 그 프로토타입은 파일에 정의될 것입니다 *.h
.
나는 사용할 것이다grep(1)
, 하지만 프로토타입의 여러 줄을 읽을 수 있기를 원했기 때문에 폐기되었습니다.
그래서 제가 보통 하는 일은 다음과 같습니다.
- 프로젝트:
glibc
- 반환 유형:
int
- 기능 이름:
cacheflush
syscall='cacheflush';
find glibc/ -name '*.h' \
|xargs sed -n "/^[a-z ]*int ${syscall}[ ]*(/,/^$/p";
그러나 이것은 내가 원하는 줄 뒤에 원하지 않는 줄을 인쇄합니다.
$ find glibc/ -name '*.h' \
|xargs sed -n "/^[a-z ]*int ${syscall}[ ]*(/,/^$/p";
extern int cacheflush (void *__addr, int __nbytes, int __op) __THROW;
#endif
extern int cacheflush (void *__addr, const int __nbytes,
const int __op) __THROW;
#endif
extern int cacheflush (void *__addr, const int __nbytes, const int __op) __THROW;
#endif
extern int _flush_cache (char *__addr, const int __nbytes, const int __op) __THROW;
extern int cacheflush (void *__addr, const int __nbytes, const int __op) __THROW;
#endif
extern int _flush_cache (char *__addr, const int __nbytes, const int __op) __THROW;
/^$/
닫는 패턴 -> 을 바꾸고 싶지만 /;/
함수 프로토타입이 여러 줄에 걸쳐 있는 경우에만 작동합니다. 당신은 말할 수 있나요sed(1)
아마도 끝 패턴이 시작 패턴과 같은 줄에 있으므로 출력은 다음과 같을까요? :
$ find glibc/ -name '*.h' | xargs sed magic;
extern int cacheflush (void *__addr, int __nbytes, int __op) __THROW;
extern int cacheflush (void *__addr, const int __nbytes,
const int __op) __THROW;
extern int cacheflush (void *__addr, const int __nbytes, const int __op) __THROW;
extern int cacheflush (void *__addr, const int __nbytes, const int __op) __THROW;
답변1
사용할 수 있는 pcregrep
여러 줄 모드 :
$ pcregrep --include='\.h$' -rM '(?s)^\s*(\w+\s+)*int cacheflush\s*\(.*?;' glibc
glibc/sysdeps/unix/sysv/linux/mips/sys/cachectl.h:extern int cacheflush (void *__addr, const int __nbytes, const int __op) __THROW;
glibc/sysdeps/unix/sysv/linux/csky/sys/cachectl.h:extern int cacheflush (void *__addr, const int __nbytes,
const int __op) __THROW;
glibc/sysdeps/unix/sysv/linux/nios2/sys/cachectl.h:extern int cacheflush (void *__addr, const int __nbytes, const int __op) __THROW;
PCRE를 사용하면 Perl의 고급 정규식 연산자 대부분에 액세스할 수 있습니다. 여기서는 다음을 사용합니다.
\w
\s
, 단어 및 공백 문자 도 포함됩니다 .(?s)
:s
플래그가.
개행 문자와도 일치하도록 합니다.*?
: 탐욕스럽지 않은 버전의*
. 그래서 일치한다첫 번째;
탐욕스러운 버전처럼 지난번 대신에 발생합니다 .
자세한 내용은 매뉴얼 페이지를 참조하십시오 pcrepattern(3)
.
답변2
두 번 호출할 필요가 없습니다 sed
. 범위를 입력하기 전에 시작/끝이 같은 줄에 있는지 확인하면 됩니다.
$ find glibc/ -name '*.h' \
|xargs sed \
-e "/${pattern}.*;\$/b" \
-e "/${pattern}/,/;\$/p" \
-e 'd' ;
find
일반 파일만 찾도록 유틸리티를 제한하면 좋을 것입니다. 그렇지 않으면 sed
이름이 다음으로 끝나는 디렉토리에서 작업할 때 경고가 표시될 수 있습니다..h
답변3
나는 (추악한) 해결책을 생각해 냈습니다.
/begin/
from to (빈 줄)을 읽고/^$/
패턴의 첫 번째 줄을 반복하여sed(1)
이는 후속 단계에서 조치를 취할 수 있습니다.사용
sed(1)
/begin/
에서 까지 찾아보세요/end/
. 사용할 수 있도록 이 단계에서 빈 줄을 남겨두세요.uniq(1)
다음 단계의 1단계에서 복제한 행을 올바르게 삭제하세요.사용
uniq(1)
중복된 행을 제거합니다.
$ syscall=cacheflush;
$ return=int;
$ pattern="^[a-z ]*${return} ${syscall}[ ]*(";
$ find glibc/ -name '*.h' \
|xargs sed -n -e "/${pattern}/p" -e "/${pattern}/,/^$/p" \
|sed -n -e "/${pattern}/,/;/p" -e '/^$/p' \
|uniq;
extern int cacheflush (void *__addr, int __nbytes, int __op) __THROW;
extern int cacheflush (void *__addr, const int __nbytes,
const int __op) __THROW;
extern int cacheflush (void *__addr, const int __nbytes, const int __op) __THROW;
extern int cacheflush (void *__addr, const int __nbytes, const int __op) __THROW;
더 간단한 솔루션을 제공해주세요 :)