/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

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;

より簡単な解決策を提供してください:)

関連情報