最近、私は で働き始めました Asciidoctor.jsおよびon Asciidoctor.js-pugおよびAsciidoctor-templates.jsプロジェクト。
数千行を含むコードベースを初めて掘り下げたときに、すぐに効果を発揮するのは必ずしも簡単ではありません。しかし、非常に多くのコード行を通り抜けるための私の秘密兵器は、grep
です。 ツール。
Linuxでgrepコマンドを使用する方法を例を挙げて説明します。
Linuxでのgrepコマンドの実際の便利な例
man
を調べると 、grep
の簡単な説明が表示されます ツール:「パターンに一致する線を印刷する」
ただし、次のような謙虚な定義に騙されないでください:grep
はUnixツールボックスで最も便利なツールの1つであり、テキストファイルを操作するとすぐに使用できる機会が無数にあります。
物事がどのように機能するかを学ぶために、実際の例を用意することをお勧めします。そこで、Asciidoctor.jsソースツリーを使用して、grep
の一部を説明します。 機能。
そのソースツリーはGitHubからダウンロードできます。必要に応じて、この記事を書いているときに使用したのと同じチェンジセットを確認することもできます。これにより、この記事の残りの部分で説明されているものと完全に同じ結果が得られます。
git clone https://github.com/asciidoctor/asciidoctor.js
cd asciidoctor.js
git checkout v1.5.6-rc.1
1。文字列のすべての出現箇所を検索します(基本的な使用法)
Asciidoctor.jsは、Javaプラットフォーム用のNashornJavaScriptエンジンをサポートしています。 Nashornを知らないので、その機会を利用して、そのJavaScriptエンジンを参照するプロジェクトパーツを探索することで、Nashornについて詳しく知ることができました。
出発点として、package.json
にNashornに関連する設定があるかどうかを確認しました。 プロジェクトの依存関係を説明するファイル:
[email protected]:~$ grep nashorn package.json
"test": "node npm/test/builder.js && node npm/test/unsupported-features.js && node npm/test/jasmine-browser.js && node npm/test/jasmine-browser-min.js && node npm/test/jasmine-node.js && node npm/test/jasmine-webpack.js && npm run test:karmaBrowserify && npm run test:karmaRequirejs && node npm/test/nashorn.js",
はい、どうやらNashorn固有のテストがいくつかありました。それでは、もう少し調べてみましょう。
2。ファイルセットでの大文字と小文字を区別しない検索
ここで、./npm/test/
のファイルを詳しく見ていきたいと思います。 Nashornに明示的に言及しているディレクトリ。
大文字と小文字を区別しない検索(-i
オプション)nashorn
への両方の参照を見つける必要があるため、ここではおそらくより良いでしょう およびNashorn
(または大文字と小文字のその他の組み合わせ):
[email protected]:~$ grep -i nashorn npm/test/*.js
npm/test/nashorn.js:const nashornModule = require('../module/nashorn');
npm/test/nashorn.js:log.task('Nashorn');
npm/test/nashorn.js:nashornModule.nashornRun('jdk1.8.0');
確かに、大文字と小文字の区別はここでは役に立ちました。そうでなければ、require('../module/nashorn')
を見逃していたでしょう。 声明。間違いなく、後でそのファイルを詳しく調べる必要があります。
3。一致しないファイルをすべて検索します
ちなみに、npm/test/
にはNashorm固有ではないファイルがいくつかありますか? ディレクトリ?その質問に答えるために、grepの「一致しないファイルを印刷する」オプションを使用できます(-L
オプション):
sh$ grep -iL nashorn npm/test/*
npm/test/builder.js
npm/test/jasmine-browser-min.js
npm/test/jasmine-browser.js
npm/test/jasmine-node.js
npm/test/jasmine-webpack.js
npm/test/unsupported-features.js
-L
の方法に注目してください オプションgrep
の出力 ファイル名のみを表示するように変更されました。したがって、上記のファイルには、文字列「nashorn」が含まれていません(大文字と小文字は関係ありません)。それは、それらがそのテクノロジーに何らかの形で関連していないという意味ではありませんが、少なくとも「n-a-s-h-o-r-n」という文字は存在しません。
4。パターンを非表示のファイルに検索し、再帰的にサブディレクトリに検索する
最後の2つのコマンドは、シェルグロブパターンを使用して、調査するファイルのリストをgrep
に渡しました。 指図。
ただし、これにはいくつかの固有の制限があります。スター(*
)非表示のファイルとは一致しません。どちらも(最終的には)サブディレクトリに含まれるファイルとは一致しません。
解決策は、grep
を組み合わせることです。 シェルグロブパターンに依存する代わりに、findコマンドを使用します。
# This is not efficient as it will spawn a new grep process for each file
[email protected]:~$ find npm/test/ -type f -exec grep -iL nashorn \{} \;
# This may have issues with filenames containing space-like characters
[email protected]:~$ grep -iL nashorn $(find npm/test/ -type f)
コメントとして上記のコードブロックで述べたように、これらのソリューションにはそれぞれ欠点があります。
スペースのような文字を含むファイル名については、grep -z
を調べてみましょう。 -print0
と組み合わせたオプション find
のオプション コマンドは、その問題を軽減することができます。この記事の最後にあるコメントセクションを使用して、そのトピックに関するアイデアを共有することを躊躇しないでください!
それでも、より良い解決策は「再帰的」(-r
)を使用することです。 )grep
のオプション 。このオプションを使用すると、コマンドラインで、調べるファイル名の明示的なリストの代わりに、検索ツリーのルート(開始ディレクトリ)を指定できます。
-r
を使用 オプションを選択すると、grepは、非表示のファイルを含む、指定されたディレクトリ内のすべてのファイルを検索し、その後、任意のサブディレクトリに再帰的に下降します。
[email protected]:~$ grep -irL nashorn npm/test/npm/
npm/test/builder.js
npm/test/jasmine-browser-min.js
npm/test/jasmine-browser.js
npm/test/jasmine-node.js
npm/test/jasmine-webpack.js
npm/test/unsupported-features.js
実際、そのオプションを使用すると、1レベル上の探索を開始して、Nashornを対象とする非npmテストもあることを確認できます。
[email protected]:~$ grep -irL nashorn npm/
そのコマンドを自分でテストして、その結果を確認します。しかし、ヒントとして、一致するファイルをもっとたくさん見つける必要があると言えます!
5。名前によるファイルのフィルタリング(正規表現を使用)
そのため、そのプロジェクトにはNashorn固有のテストがいくつかあるようです。 NashornはJavaであるため、提起される可能性のある別の質問は、 「プロジェクトにNashornに明示的に言及しているJavaソースファイルがいくつかありますか?」です。 。
grep
のバージョンによって異なります 使用する場合、その質問に答えるには少なくとも2つの解決策があります。
1つ目は、grep
を使用することです。 パターン「nashorn」を含むすべてのファイルを検索するには、その最初のコマンドの出力を2番目のgrep
にパイプします。 インスタンスがJava以外のソースファイルを除外する:
[email protected]:~$ grep -ir nashorn ./ | grep "^[^:]*\.java"
./spec/nashorn/AsciidoctorConvertWithNashorn.java:public class AsciidoctorConvertWithNashorn {
./spec/nashorn/AsciidoctorConvertWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn");
./spec/nashorn/AsciidoctorConvertWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/asciidoctor-convert.js"));
./spec/nashorn/BasicJavascriptWithNashorn.java:public class BasicJavascriptWithNashorn {
./spec/nashorn/BasicJavascriptWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn");
./spec/nashorn/BasicJavascriptWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/basic.js"));
コマンドの前半は、これで理解できるはずです。しかし、その「^ [\ ^:] * \\。java」の部分はどうですか?
-F
を指定しない限り オプション、grep
検索パターンが正規表現であると想定しています。つまり、逐語的に一致するプレーン文字に加えて、より複雑なパターンを記述するためのメタ文字のセットにアクセスできます。上で使用したパターンは一致するだけです:
-
^
行の始まり -
[^:]*
コロン以外の文字のシーケンスが続く \.
後にドットが続きます(ドットは regexで特別な意味を持ちます 、文字通りの一致が必要であることを表すために、バックスラッシュで保護する必要がありました)-
java
その後に「java」という4文字が続きます。
実際には、grep
コロンを使用してファイル名をコンテキストから分離します。.java
を持つ行のみを保持します ファイル名セクション。言及する価値があります .javascript
にも一致します ファイル名。これは、必要に応じて自分で解決してみようと思います。
6。 grepを使用した名前によるファイルのフィルタリング
正規表現は非常に強力です。しかし、その特定のケースでは、それはやり過ぎのようです。上記の解決策については言及していませんが、「nashorn」パターンを探すためにすべてのファイルを調べることに時間を費やしています。ほとんどの結果は、パイプラインの2番目のステップで破棄されます。
GNUバージョンのgrep
を使用している場合 、Linuxを使用している場合は、--include
を使用しても別の解決策があります。 オプション。これはgrep
に指示します 指定されたグロブパターンに一致する名前のファイルのみを検索するには:
[email protected]:~$ grep -ir nashorn ./ --include='*.java'
./spec/nashorn/AsciidoctorConvertWithNashorn.java:public class AsciidoctorConvertWithNashorn {
./spec/nashorn/AsciidoctorConvertWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn");
./spec/nashorn/AsciidoctorConvertWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/asciidoctor-convert.js"));
./spec/nashorn/BasicJavascriptWithNashorn.java:public class BasicJavascriptWithNashorn {
./spec/nashorn/BasicJavascriptWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn");
./spec/nashorn/BasicJavascriptWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/basic.js"));
7。単語を探す
Asciidoctor.jsプロジェクトの興味深い点は、多言語プロジェクトであるということです。 Asciidoctorは基本的にRubyで記述されているため、JavaScriptの世界で使用するには、RubyからJavaScriptへのソースツーソースコンパイラであるOpalを使用して「トランスパイル」する必要があります。以前は知らなかったもう1つのテクノロジー。
そこで、Nashornの特異性を調べた後、OpalAPIをよりよく理解するタスクを自分に割り当てました。その探求の最初のステップとして、私はOpal
のすべての言及を検索しました プロジェクトのJavaScriptファイル内のグローバルオブジェクト。影響で表示される可能性があります(Opal =
)、メンバーアクセス(Opal.
)または他のコンテキストでも。正規表現でうまくいきます。ただし、もう一度、grep
その一般的なユースケースを解決するためのより軽量なソリューションがあります。 -w
を使用する オプションの場合、単語のみに一致します 、つまり、単語以外の文字の前後のパターンです。単語以外の文字とは、行の先頭、行の終わり、または文字でも数字でもアンダースコアでもない文字のいずれかです。
[email protected]:~$ grep -irw --include='*.js' Opal .
...
8。出力の色付け
一致するものが多いため、前のコマンドの出力をコピーしませんでした。このように出力が密集している場合は、わかりやすくするために少し色を追加することをお勧めします。これがシステムでデフォルトでまだ構成されていない場合は、GNU --color
を使用してその機能をアクティブ化できます。 オプション:
[email protected]:~$ grep -irw --color=auto --include='*.js' Opal .
...
以前と同じ長い結果が得られるはずですが、まだそうでない場合は、今回は検索文字列がカラーで表示されるはずです。
9。一致する行または一致するファイルを数える
前のコマンドの出力が非常に長いことを2回述べました。正確にはどのくらいですか?
[email protected]:~$ grep -irw --include='*.js' Opal . | wc -l
86
つまり、合計があります すべての86の一致する行 調べたファイル。しかし、いくつの異なるファイルが一致していますか? -l
を使用 オプションで、grep
を制限できます 一致するファイルを出力します 一致する行を表示する代わりに 。そのため、簡単な変更で、一致するファイルの数がわかります。
[email protected]:~$ grep -irwl --include='*.js' Opal . | wc -l
20
それが-L
を思い出させるなら オプション、当然のことながら、比較的一般的であるため、補完的なオプションを区別するために小文字/大文字が使用されます。 -l
一致するファイル名を表示します。 -L
一致しないファイル名を表示します。別の例として、-h
のマニュアルを確認させてください / -H
オプション。
その括弧を閉じて、結果に戻りましょう:86の一致する行。 20個の一致するファイル。ただし、一致する行はどのように配布されますか 一致するファイル ? -c
を使用するとわかります grep
のオプション 調べたファイル(一致がゼロのファイルを含む)ごとに一致する行の数をカウントします:
[email protected]:~$ grep -irwc --include='*.js' Opal .
...
多くの場合、その出力には、ファイルが調べられた順序で結果が表示され、一致しないファイルも含まれるため、後処理が必要になります。これは通常、私たちには関係ありません。後者は非常に簡単に解決できます:
[email protected]:~$ grep -irwc --include='*.js' Opal . | grep -v ':0$'
注文については、パイプラインの最後に並べ替えコマンドを追加できます。
[email protected]:~$ grep -irwc --include='*.js' Opal . | grep -v ':0$' | sort -t: -k2n
sort
を確認させてください 使用したオプションの正確な意味については、コマンドマニュアルを参照してください。以下のコメントセクションを使用して、調査結果を共有することを忘れないでください!
10。 2つの一致するセットの違いを見つける
覚えているかと思いますが、数コマンド前に、単語を検索しました。 "オパール。"ただし、同じファイルセットで文字列のすべての出現箇所を検索すると 「オパール」私はさらに約20の答えを得る:
[email protected]:~$ grep -irw --include='*.js' Opal . | wc -l
86
[email protected]:~$ grep -ir --include='*.js' Opal . | wc -l
105
これらの2つのセットの違いを見つけることは興味深いでしょう。では、4文字の「オパール」が連続して含まれているが、これらの4文字が単語全体を形成していない行は何ですか?
これは、その質問に答えるのはそれほど簡単ではありません。 同じ 行には両方を含めることができます オパールという単語と、これらの4文字を含むいくつかの大きな単語。ただし、最初の概算として、そのパイプラインを使用できます。
[email protected]:~$ grep -ir --include='*.js' Opal . | grep -ivw Opal
./npm/examples.js: const opalBuilder = OpalBuilder.create();
./npm/examples.js: opalBuilder.appendPaths('build/asciidoctor/lib');
./npm/examples.js: opalBuilder.appendPaths('lib');
...
どうやら、私の次の目的はopalBuilder
を調査することです オブジェクトですが、それはまた別の日です。
もちろん、grep
をいくつか発行するだけでは、プロジェクトの組織を理解することはできません。コードアーキテクチャを理解することはできません。 コマンド!
ただし、新しいコードベースを探索するときにベンチマークと開始点を特定するために、そのコマンドは避けられないことがわかりました。
したがって、この記事がgrep
の力を理解するのに役立つことを願っています。 コマンドを実行し、ツールチェストに追加します。後悔しないこと間違いなしです!