🎉

ripgrep usage

2021/12/25に公開

ag / The silver searcherをgrep代わりに使っていたのだけど、
ripgrepのほうが更に早くて良いっぽいとの噂だったので使い方調べた.

ripgrep

ripgrep
はrustで記述され正規表現で検索できる、行ベースのディレクトリ再帰タイプの検索ツール.

win/mac/linuxで利用できて、grep,ack,agなんかよりもより素早く検索できるとのこと.

公式のベンチを見ると、git grepなんかよりも10倍早いっぽい

install

brewで入った. cargoとかでも行けるっぽい

$ brew install ripgrep

usage

まずはhelpを眺める

$ rg --help
ripgrep 13.0.0
Andrew Gallant <jamslam@gmail.com>

ripgrep (rg) recursively searches the current directory for a regex pattern.
By default, ripgrep will respect gitignore rules and automatically skip hidden
files/directories and binary files.

Use -h for short descriptions and --help for more details.

Project home page: https://github.com/BurntSushi/ripgrep


USAGE:
    rg [OPTIONS] PATTERN [PATH ...]
    rg [OPTIONS] -e PATTERN ... [PATH ...]
    rg [OPTIONS] -f PATTERNFILE ... [PATH ...]
    rg [OPTIONS] --files [PATH ...]
    rg [OPTIONS] --type-list
    command | rg [OPTIONS] PATTERN
    rg [OPTIONS] --help
    rg [OPTIONS] --version

基本的にpatternを第一引数として、第2引数以降にpathを指定するっぽい

普通に検索

下記のようなフォーマットでファイルごとに行番号付きで見やすく表示してくれた.

$ rg '\s+UnityEngine' Assets/Scripts
Assets/Scripts/SimpleCameraController.cs
2:using UnityEngine.InputSystem;
5:using UnityEngine;

Assets/Scripts/Domain/Entity/TileMap.cs
4:using UnityEngine.Assertions;

Assets/Scripts/Domain/Entity/TileSet.cs
3:using UnityEngine;

2つ以降pathをつなげていくとOR条件で検索場所を増やせる

$ rg '\s+UnityEngine' Assets/Scripts/Domain ProjectSettings/
Assets/Scripts/Domain/Entity/TileSet.cs
3:using UnityEngine;

Assets/Scripts/Domain/Entity/TileMap.cs
4:using UnityEngine.Assertions;

ProjectSettings/GraphicsSettings.asset
70:    UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 2109e40bb998a408480bab0cd226b766, type: 2}

pipe

pipeでつなげると、出力フォーマットは自動で変更して、1行1マッチで表示してくれる. (行番号はない)
pipeで挙動を変えるのIFってなんか気遣ってる感がいいよね.

$ rg '\s+UnityEngine' Assets/Scripts | tee /tmp/rg.log
Assets/Scripts/Domain/Entity/TileMap.cs:using UnityEngine.Assertions;
Assets/Scripts/SimpleCameraController.cs:using UnityEngine.InputSystem;
Assets/Scripts/SimpleCameraController.cs:using UnityEngine;
Assets/Scripts/Domain/Entity/TileSet.cs:using UnityEngine;
Assets/Scripts/UI/KeyboardInput.cs:using UnityEngine;
Assets/Scripts/UI/TileMapBinder.cs:using UnityEngine;
Assets/Scripts/UI/TileRenderer.cs:using UnityEngine;
Assets/Scripts/UI/TileMapRenderer.cs:using UnityEngine;
Assets/Scripts/UI/TileMapRenderer.cs:using UnityEngine.Assertions;
Assets/Scripts/UI/SetTileMapButton.cs:using UnityEngine;
Assets/Scripts/UI/SetTileMapButton.cs:using UnityEngine.UI;

正規表現

正規表現は、rust標準のものに対応しているとのこと. pcreっぽい書き方 (\s とか) に対応しているのはとても嬉しい.
sedとか古臭いコマンドだとここらへんの正規表現が使いづらいんよな..

--column

--columnで行番号に絡む番号を追加して表示

$ rg '\s+UnityEngine' Assets/Scripts/Domain ProjectSettings/ --column
Assets/Scripts/Domain/Entity/TileMap.cs
4:6:using UnityEngine.Assertions;

Assets/Scripts/Domain/Entity/TileSet.cs
3:6:using UnityEngine;

ProjectSettings/GraphicsSettings.asset
70:1:    UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 2109e40bb998a408480bab0cd226b766, type: 2}

$ rg '\s+UnityEngine' Assets/Scripts/Domain ProjectSettings/ --column | tee /tmp/debug.log
ProjectSettings/GraphicsSettings.asset:70:1:    UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 2109e40bb998a408480bab0cd226b766, type: 2}
Assets/Scripts/Domain/Entity/TileSet.cs:3:6:using UnityEngine;
Assets/Scripts/Domain/Entity/TileMap.cs:4:6:using UnityEngine.Assertions;

-C NUM / -B NUM / -A NUM

grepの -C/-B/-A に対応するようなオプション.
マッチした場所の前後指定行数を表示、Aはafter(以後),Bはbefore(以前),Cはcontext(前後).

$ rg '\s+m_PreloadedShaders' ProjectSettings/ -A 2
ProjectSettings/GraphicsSettings.asset
43:  m_PreloadedShaders: []
44-  m_PreloadShadersBatchTimeLimit: -1
45-  m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0}

$ rg '\s+m_PreloadedShaders' ProjectSettings/ -B 2
ProjectSettings/GraphicsSettings.asset
41-  - {fileID: 16001, guid: 0000000000000000f000000000000000, type: 0}
42-  - {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0}
43:  m_PreloadedShaders: []

$ rg '\s+m_PreloadedShaders' ProjectSettings/ -C 2
ProjectSettings/GraphicsSettings.asset
41-  - {fileID: 16001, guid: 0000000000000000f000000000000000, type: 0}
42-  - {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0}
43:  m_PreloadedShaders: []
44-  m_PreloadShadersBatchTimeLimit: -1
45-  m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0}

-c

-cでファイルごとにマッチした回数を表示.

$ rg '\s+Unity' Assets/Scripts -c
Assets/Scripts/SimpleCameraController.cs:4
Assets/Scripts/Application/HookKeys.cs:1
Assets/Scripts/Domain/Entity/TileMap.cs:1
Assets/Scripts/UI/SetTileMapButton.cs:3
Assets/Scripts/UI/TileMapBinder.cs:2
Assets/Scripts/UI/KeyboardInput.cs:2
Assets/Scripts/UI/TileMapRenderer.cs:2
Assets/Scripts/UI/TileRenderer.cs:1
Assets/Scripts/Domain/Entity/TileSet.cs:1

-l

マッチしたフィアルリストを表示する

$ rg '\s+Unity' Assets/Scripts -l
Assets/Scripts/SimpleCameraController.cs
Assets/Scripts/Application/HookKeys.cs
Assets/Scripts/UI/KeyboardInput.cs
Assets/Scripts/Domain/Entity/TileMap.cs
Assets/Scripts/Domain/Entity/TileSet.cs
Assets/Scripts/UI/TileMapBinder.cs
Assets/Scripts/UI/TileRenderer.cs
Assets/Scripts/UI/TileMapRenderer.cs
Assets/Scripts/UI/SetTileMapButton.cs

--heading / --no-heading

defaultでpipeのおきに挙動を切り替えていたような1行スタイルとファイルごとのマッチスタイルを切り替える.

$ rg '\s+Unity' ProjectSettings --no-heading
ProjectSettings/GraphicsSettings.asset:70:    UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 2109e40bb998a408480bab0cd226b766, type: 2}
ProjectSettings/UnityConnectSettings.asset:19:  UnityPurchasingSettings:
ProjectSettings/UnityConnectSettings.asset:22:  UnityAnalyticsSettings:
ProjectSettings/UnityConnectSettings.asset:26:  UnityAdsSettings:
$ rg '\s+Unity' ProjectSettings --heading
ProjectSettings/UnityConnectSettings.asset
19:  UnityPurchasingSettings:
22:  UnityAnalyticsSettings:
26:  UnityAdsSettings:

ProjectSettings/GraphicsSettings.asset
70:    UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 2109e40bb998a408480bab0cd226b766, type: 2}

--json

--json 出力もできるっぽい.
なんか他のコマンドと組み合わせて解析するときにも便利そう

$ rg '\s+UnityE' ProjectSettings --json
{"type":"begin","data":{"path":{"text":"ProjectSettings/GraphicsSettings.asset"}}}
{"type":"match","data":{"path":{"text":"ProjectSettings/GraphicsSettings.asset"},"lines":{"text":"    UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 2109e40bb998a408480bab0cd226b766, type: 2}\n"},"line_number":70,"absolute_offset":2636,"submatches":[{"match":{"text":"    UnityE"},"start":0,"end":10}]}}
{"type":"end","data":{"path":{"text":"ProjectSettings/GraphicsSettings.asset"},"binary_offset":null,"stats":{"elapsed":{"secs":0,"nanos":58750,"human":"0.000059s"},"searches":1,"searches_with_match":1,"bytes_searched":2765,"bytes_printed":422,"matched_lines":1,"matches":1}}}
{"data":{"elapsed_total":{"human":"0.005132s","nanos":5132500,"secs":0},"stats":{"bytes_printed":422,"bytes_searched":2765,"elapsed":{"human":"0.000059s","nanos":58750,"secs":0},"matched_lines":1,"matches":1,"searches":1,"searches_with_match":1}},"type":"summary"}

-n --line-number

行数表示をするか否か、defaultのpipeだと行数表示してくれないのでそれと組み合わせるとよさそう

$ rg '\s+UnityE' ProjectSettings | tee /tmp/rg.log
ProjectSettings/GraphicsSettings.asset:    UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 2109e40bb998a408480bab0cd226b766, type: 2}
$ rg '\s+UnityE' ProjectSettings -n | tee /tmp/rg.log
ProjectSettings/GraphicsSettings.asset:70:    UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 2109e40bb998a408480bab0cd226b766, type: 2}

-max-depth NUM

directoryの深さを指定できる

$ rg '\s+UnityE' Assets --max-depth 2
Assets/Scripts/SimpleCameraController.cs
2:using UnityEngine.InputSystem;
5:using UnityEngine;
171:                UnityEditor.EditorApplication.isPlaying = false;

-U / --multiline

複数行を超えたマッチもかける

$ rg 'InputSystem;\s+#endif' Assets/Scripts --multiline
Assets/Scripts/SimpleCameraController.cs
2:using UnityEngine.InputSystem;
3:#endif

-q

quiet modeで何も出力しない. exit codeがマッチしているかどうかで変わる.
match有無を判定するshellの処理に良さそう

$ rg 'InputSystem;a' Assets/Scripts -q; echo $?
1
$ rg 'InputSystem;' Assets/Scripts -q; echo $?
0

-r / --replace

マッチした部分を置換してくれるっぽい.
元ファイルは書き換えない.

$ cat /tmp/a.txt
Hello, John!
Hello, John!
$ rg 'John' /tmp/a.txt --replace 'Bob'
1:Hello, Bob!
2:Hello, Bob!
$ cat /tmp/a.txt
Hello, John!
Hello, John!

--sort SORTBY / --sortr SORTBY

none/path/modified/accessed/createdでマッチした表示順をファイル単位で変更してくれるっぽい.
--sortr は逆順に表示.
地味に便利で使いそう.

$ rg '\s+UnityE' Assets -l
Assets/Scripts/SimpleCameraController.cs
Assets/Scripts/UI/SetTileMapButton.cs
Assets/Scripts/UI/TileRenderer.cs
Assets/Imports/CustomizableSkybox/Model/Low Poly Island.fbx.meta
Assets/Scripts/UI/TileMapBinder.cs
Assets/Scripts/UI/KeyboardInput.cs
Assets/Scripts/UI/TileMapRenderer.cs
Assets/Scripts/Domain/Entity/TileSet.cs
Assets/Scripts/Domain/Entity/TileMap.cs
$ rg '\s+UnityE' Assets -l --sort created
Assets/Scripts/SimpleCameraController.cs
Assets/Scripts/UI/TileMapRenderer.cs
Assets/Scripts/UI/TileRenderer.cs
Assets/Scripts/UI/SetTileMapButton.cs
Assets/Scripts/UI/KeyboardInput.cs
Assets/Scripts/UI/TileMapBinder.cs
Assets/Scripts/Domain/Entity/TileSet.cs
Assets/Scripts/Domain/Entity/TileMap.cs
Assets/Imports/CustomizableSkybox/Model/Low Poly Island.fbx.meta
$ rg '\s+UnityE' Assets -l --sortr created
Assets/Imports/CustomizableSkybox/Model/Low Poly Island.fbx.meta
Assets/Scripts/Domain/Entity/TileMap.cs
Assets/Scripts/Domain/Entity/TileSet.cs
Assets/Scripts/UI/TileMapBinder.cs
Assets/Scripts/UI/KeyboardInput.cs
Assets/Scripts/UI/SetTileMapButton.cs
Assets/Scripts/UI/TileRenderer.cs
Assets/Scripts/UI/TileMapRenderer.cs
Assets/Scripts/SimpleCameraController.cs

おわり

まだまだオプション盛りだくさんだった.
オプション知ってるだけで、使い方の幅が広がるのでmanとかhelpを一度ざっと眺めるの大事だ.
ripgrepかなり高速で使い勝手もいいので今後はgrep代わりに利用しよう.

Discussion