/begin/에서 /end/까지 파일을 읽는 방법(둘 다 같은 줄에 있을 수 있는 경우)

/begin/에서 /end/까지 파일을 읽는 방법(둘 다 같은 줄에 있을 수 있는 경우)

대규모 프로젝트의 소스코드를 통해 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

나는 (추악한) 해결책을 생각해 냈습니다.

  1. /begin/from to (빈 줄)을 읽고 /^$/패턴의 첫 번째 줄을 반복하여sed(1)이는 후속 단계에서 조치를 취할 수 있습니다.

  2. 사용sed(1)/begin/에서 까지 찾아보세요 /end/. 사용할 수 있도록 이 단계에서 빈 줄을 남겨두세요.uniq(1)다음 단계의 1단계에서 복제한 행을 올바르게 삭제하세요.

  3. 사용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;

더 간단한 솔루션을 제공해주세요 :)

관련 정보