Skilore

パターン検索(grep / ripgrep)

grep は「テキストの中から必要な行を抽出する」最も重要なフィルタリングツール。

81 分で読めます40,024 文字

パターン検索(grep / ripgrep)

grep は「テキストの中から必要な行を抽出する」最も重要なフィルタリングツール。

この章で学ぶこと

  • grep の主要オプションを使いこなせる
  • 正規表現を活用した検索ができる
  • ripgrep(rg)で高速な再帰検索ができる
  • grep 系ツール(egrep, fgrep, ag, ack)の使い分けができる
  • 実務で頻出する検索パターンを身につける

前提知識

このガイドを読む前に、以下の知識があると理解が深まります:

  • 基本的なプログラミングの知識
  • 関連する基礎概念の理解
  • ファイル表示 の内容を理解していること

1. grep の基本

1.1 基本構文と動作

# 基本構文: grep [オプション] パターン [ファイル...]
#
# grep は入力の各行に対してパターンをマッチングし、
# マッチした行を標準出力に出力する。
# パターンはデフォルトで基本正規表現(BRE)として解釈される。
 
# 基本的な文字列検索
grep "error" logfile.txt            # "error" を含む行を表示
grep "warning" logfile.txt          # "warning" を含む行を表示
grep "fatal" logfile.txt            # "fatal" を含む行を表示
 
# ファイルを指定しない場合は標準入力から読む
echo "hello world" | grep "world"   # "world" を含む行
ps aux | grep nginx                 # パイプ経由で検索
cat /etc/passwd | grep "root"       # /etc/passwd から root を検索
 
# 複数ファイルの検索
grep "error" *.log                  # 全 .log ファイルから検索
grep "TODO" src/*.py                # Python ファイルから TODO を検索
grep "import" lib/*.js              # JS ファイルから import を検索

1.2 主要オプション(出力制御)

# -i: 大小文字を無視(ignore case)
grep -i "error" logfile.txt         # Error, ERROR, error 全てマッチ
grep -i "warning" logfile.txt       # Warning, WARNING 等もマッチ
 
# -n: 行番号を表示
grep -n "error" logfile.txt         # "42:error occurred" のように行番号付き
grep -n "TODO" src/*.py             # ファイル名:行番号:マッチ行
 
# -c: マッチした行数をカウント
grep -c "error" logfile.txt         # マッチ行数を数値で表示
grep -c "error" *.log               # 各ファイルのマッチ行数
 
# -l: マッチしたファイル名のみ表示(ファイル内容は表示しない)
grep -l "error" *.log               # error を含むログファイルの名前
grep -rl "TODO" src/                # 再帰的に TODO を含むファイル名
grep -rL "test" src/                # test を含まないファイル名(-L は -l の逆)
 
# -v: 逆マッチ(マッチしない行を表示)
grep -v "debug" logfile.txt         # debug を含まない行
grep -v "^#" config.conf            # コメント行以外
grep -v "^$" file.txt               # 空行以外
 
# -w: 単語として完全一致(word match)
grep -w "error" logfile.txt         # "error" に完全一致("errors" はマッチしない)
grep -w "log" file.txt              # "log" に一致("logging" はマッチしない)
grep -w "main" *.py                 # 単語 "main" を検索
 
# -x: 行全体が完全一致
grep -x "hello" file.txt            # 行全体が "hello" の行のみ
 
# -o: マッチした部分のみ表示(行全体ではなく)
grep -o "error[a-z]*" logfile.txt   # "error" で始まる単語だけ抽出
grep -oP "\d+\.\d+\.\d+\.\d+" access.log  # IPアドレスを抽出
 
# -q: 何も出力しない(終了コードのみ、スクリプト用)
if grep -q "error" logfile.txt; then
    echo "エラーが見つかりました"
fi

1.3 コンテキスト表示(-A / -B / -C)

# -A N: マッチ行の後(After)N行も表示
grep -A 3 "error" logfile.txt       # マッチ行 + 後3行
grep -A 5 "Exception" app.log       # 例外発生行 + スタックトレース5行
 
# -B N: マッチ行の前(Before)N行も表示
grep -B 2 "error" logfile.txt       # 前2行 + マッチ行
grep -B 5 "FATAL" app.log           # エラー前の文脈を確認
 
# -C N: マッチ行の前後(Context)N行を表示
grep -C 2 "error" logfile.txt       # 前2行 + マッチ行 + 後2行
grep -C 3 "segfault" /var/log/kern.log  # セグフォルト前後3行
 
# コンテキスト表示の区切り
# 複数のマッチがある場合、"--" で区切られる
grep -C 1 "error" logfile.txt
# → マッチブロック間に "--" が表示される
 
# グループセパレータの変更
grep --group-separator="===" -C 2 "error" logfile.txt

1.4 再帰検索(-r / -R)

# -r: ディレクトリを再帰的に検索
grep -r "TODO" ./src/               # src/ 以下を再帰検索
grep -r "import os" ./              # カレントディレクトリ以下を検索
grep -rn "console.log" ./src/       # 行番号付きで再帰検索
 
# -R: -r と同等だが、シンボリックリンクもたどる
grep -R "pattern" /etc/             # シンボリックリンク先も検索
 
# --include: 特定のファイルパターンのみ検索
grep -rn --include="*.py" "import" ./src/     # .py ファイルのみ
grep -rn --include="*.{js,ts}" "fetch" ./src/ # .js と .ts のみ
grep -rn --include="*.go" "func main" ./      # .go ファイルのみ
 
# --exclude: 特定のファイルパターンを除外
grep -rn --exclude="*.min.js" "function" ./   # minified JS を除外
grep -rn --exclude="*.pyc" "import" ./        # .pyc を除外
 
# --exclude-dir: 特定のディレクトリを除外
grep -rn --exclude-dir=node_modules "require" ./       # node_modules 除外
grep -rn --exclude-dir=.git "TODO" ./                  # .git 除外
grep -rn --exclude-dir={node_modules,.git,dist} "pattern" ./  # 複数除外
 
# 実務でよく使う再帰検索パターン
grep -rn --include="*.py" --exclude-dir={__pycache__,.git,venv} "TODO\|FIXME\|HACK" ./
grep -rn --include="*.{js,ts,jsx,tsx}" --exclude-dir={node_modules,.next,dist} "console.log" ./

1.5 複数パターンの検索

# -e: 複数パターンの OR 検索
grep -e "error" -e "warning" logfile.txt        # error OR warning
grep -e "fatal" -e "critical" -e "error" app.log  # 3つのパターン
 
# -f: ファイルからパターンを読み込み
cat > patterns.txt << 'EOF'
error
warning
fatal
EOF
grep -f patterns.txt logfile.txt    # ファイル内のパターンで検索
 
# パイプで AND 検索
grep "error" logfile.txt | grep "database"    # error AND database
grep "error" logfile.txt | grep -v "timeout"  # error AND NOT timeout
 
# 正規表現で OR 検索(-E = 拡張正規表現)
grep -E "error|warning|fatal" logfile.txt     # OR 検索
grep -E "(error|warning)" logfile.txt         # グループ化
 
# AND 検索の別の方法(awk を使用)
awk '/error/ && /database/' logfile.txt       # error AND database を含む行

2. 正規表現の活用

2.1 基本正規表現(BRE)と拡張正規表現(ERE)

# grep はデフォルトで基本正規表現(BRE)を使用
# -E オプション(または egrep)で拡張正規表現(ERE)を使用
# -P オプションで Perl 互換正規表現(PCRE)を使用(GNU grep のみ)
 
# BRE と ERE の違い:
# BRE: +, ?, |, (), {} はリテラル。エスケープ \+, \?, \|, \(\), \{\} でメタ文字
# ERE: +, ?, |, (), {} がメタ文字。エスケープ不要
 
# BRE の例
grep "error\|warning" logfile.txt              # OR(BRE)
grep "ab\{2,4\}" file.txt                      # a の後に b が 2〜4個(BRE)
grep "\(abc\)\{2\}" file.txt                   # "abc" が2回繰り返し(BRE)
 
# ERE の例(-E / egrep)
grep -E "error|warning" logfile.txt            # OR(ERE、エスケープ不要)
grep -E "ab{2,4}" file.txt                     # a の後に b が 2〜4個(ERE)
grep -E "(abc){2}" file.txt                    # "abc" が2回繰り返し(ERE)

2.2 正規表現メタ文字リファレンス

# === アンカー ===
grep "^Error" logfile.txt            # 行頭が "Error"
grep "done$" logfile.txt             # 行末が "done"
grep "^$" file.txt                   # 空行
grep -E "^\s*$" file.txt             # 空白のみの行(空行含む)
 
# === 文字クラス ===
grep "[abc]" file.txt                # a, b, c のいずれか
grep "[a-z]" file.txt                # 小文字アルファベット
grep "[A-Z]" file.txt                # 大文字アルファベット
grep "[0-9]" file.txt                # 数字
grep "[^0-9]" file.txt               # 数字以外
 
# === 量指定子 ===
grep -E "ab?" file.txt               # a の後に b が 0 または 1個
grep -E "ab+" file.txt               # a の後に b が 1個以上
grep -E "ab*" file.txt               # a の後に b が 0個以上
grep -E "ab{3}" file.txt             # a の後に b がちょうど3個
grep -E "ab{2,5}" file.txt           # a の後に b が 2〜5個
grep -E "ab{3,}" file.txt            # a の後に b が 3個以上
 
# === ワイルドカード ===
grep "a.b" file.txt                  # a の後に任意の1文字、その後 b
grep "a.*b" file.txt                 # a と b の間に任意の文字列
 
# === グループ化と後方参照 ===
grep -E "(abc){2}" file.txt          # "abcabc" にマッチ
grep -E "(error|warn)" logfile.txt   # "error" または "warn"
grep "\(.*\)\1" file.txt             # 同じ文字列の繰り返し(後方参照、BRE)
 
# === 単語境界 ===
grep "\berror\b" logfile.txt         # 単語 "error"(\b = 単語境界)
grep "\<error\>" logfile.txt         # 同上(\< = 単語先頭、\> = 単語末尾)
grep -w "error" logfile.txt          # -w オプション(同等)

2.3 Perl 互換正規表現(PCRE)

# -P オプション(GNU grep のみ。macOS の grep では非対応)
# macOS では brew install grep で ggrep を使うか、ripgrep を使う
 
# \d: 数字([0-9] と同等)
grep -P "\d{4}-\d{2}-\d{2}" logfile.txt        # 日付パターン(YYYY-MM-DD)
 
# \w: 英数字とアンダースコア([a-zA-Z0-9_] と同等)
grep -P "\w+@\w+\.\w+" file.txt                # メールアドレスの簡易マッチ
 
# \s: 空白文字
grep -P "status:\s+\d{3}" access.log           # ステータスコード
 
# 先読み・後読み(lookahead / lookbehind)
grep -P "(?<=price: )\d+" file.txt             # "price: " の後の数字(後読み)
grep -P "\d+(?= yen)" file.txt                 # " yen" の前の数字(先読み)
grep -P "(?<!no )error" logfile.txt            # "no " が前にない "error"(否定後読み)
grep -P "error(?! ignored)" logfile.txt        # " ignored" が後にない "error"(否定先読み)
 
# 名前付きキャプチャ
grep -oP "(?P<ip>\d+\.\d+\.\d+\.\d+)" access.log  # IPアドレスを抽出
 
# 非貪欲マッチ
grep -oP '".*?"' file.txt                       # 最短一致の引用符内テキスト
grep -oP '<.*?>' file.html                      # HTMLタグ(最短一致)

2.4 よく使う正規表現パターン集

# --- 日付・時刻 ---
grep -E "^[0-9]{4}-[0-9]{2}-[0-9]{2}" logfile.txt         # YYYY-MM-DD 形式
grep -E "[0-9]{2}:[0-9]{2}:[0-9]{2}" logfile.txt           # HH:MM:SS 形式
grep -P "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}" logfile.txt # ISO 8601 形式
 
# --- IPアドレス ---
grep -E "\b[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\b" access.log
grep -oP "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b" access.log  # IP抽出
 
# --- メールアドレス ---
grep -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" file.txt
 
# --- URL ---
grep -E "https?://[a-zA-Z0-9./?&=%-]+" file.txt
grep -oP "https?://[^\s\"'>]+" file.html                     # URL 抽出
 
# --- HTTP ステータスコード ---
grep -E "HTTP/[0-9.]+ [0-9]{3}" access.log
grep -E "\s(4[0-9]{2}|5[0-9]{2})\s" access.log              # 4xx/5xx エラー
 
# --- JSON のキー検索 ---
grep -oP '"name"\s*:\s*"[^"]*"' data.json
grep -oP '"version"\s*:\s*"[^"]*"' package.json
 
# --- プログラミング ---
grep -E "^(def|class) " *.py                                 # Python の関数/クラス定義
grep -E "^(function|const|let|var) " *.js                    # JS の関数/変数定義
grep -E "^func " *.go                                        # Go の関数定義
grep -E "^(pub )?fn " *.rs                                   # Rust の関数定義

3. grep の高度な使い方

3.1 grep + パイプの実務パターン

# プロセス検索(自分自身を除外するテクニック)
ps aux | grep "[n]ginx"             # grep 自身を除外([n] トリック)
ps aux | grep nginx | grep -v grep  # grep -v で除外(従来の方法)
pgrep -la nginx                     # pgrep を使う(推奨)
 
# コマンド履歴から検索
history | grep "git push"           # Git push の履歴
history | grep "docker" | tail -20  # Docker 関連の直近20件
 
# パッケージ検索
dpkg -l | grep "python"             # インストール済み Python パッケージ
pip list | grep "django"            # Django 関連パッケージ
npm list | grep "react"             # React 関連パッケージ
 
# ネットワーク情報の検索
netstat -tlnp | grep ":80"          # ポート80を使用しているプロセス
ss -tlnp | grep ":443"              # ポート443を使用しているプロセス
ip addr | grep "inet "              # IPアドレスの確認
 
# Docker 関連
docker ps | grep -i running         # 稼働中のコンテナ
docker images | grep "<none>"       # 名前のないイメージ(dangling)
docker logs container 2>&1 | grep "ERROR"  # コンテナログからエラー検索
 
# Git 関連
git log --oneline | grep "fix"      # fix を含むコミット
git diff | grep "^+"                # 追加された行のみ
git branch -a | grep "feature"      # feature ブランチの一覧

3.2 grep の出力のカスタマイズ

# --color: マッチ部分をカラー表示
grep --color=always "error" logfile.txt   # 常にカラー
grep --color=auto "error" logfile.txt     # 端末出力時のみカラー(デフォルト)
grep --color=never "error" logfile.txt    # カラー無効
 
# カラーをパイプで保持する
grep --color=always "error" logfile.txt | less -R
 
# -H / -h: ファイル名の表示制御
grep -H "pattern" file.txt          # ファイル名を常に表示
grep -h "pattern" *.txt             # ファイル名を非表示
 
# -Z: ファイル名の区切りをNULL文字に(xargs -0 と組み合わせ)
grep -rlZ "pattern" . | xargs -0 sed -i 's/pattern/replacement/g'
 
# --label: 標準入力に対するラベルを指定
cat file.txt | grep --label="STDIN" -H "pattern"
 
# -m N: 最初のN件のマッチで停止
grep -m 5 "error" large_logfile.txt      # 最初の5件のみ
grep -m 1 "pattern" file.txt             # 最初の1件のみ(存在確認)
 
# カウントとファイル名の組み合わせ
grep -rc "TODO" ./src/ | grep -v ":0$" | sort -t: -k2 -rn
# → TODO を含むファイルを、TODO の数の降順で表示

3.3 grep の特殊なオプション

# -F: 固定文字列として検索(正規表現を無効化、高速)
grep -F "error.log" file.txt         # ドットをリテラルとして検索
grep -F "[ERROR]" logfile.txt        # 角括弧をリテラルとして検索
grep -F "$HOME" script.sh            # $HOME をリテラルとして検索
 
# fgrep は grep -F と同等
fgrep "pattern" file.txt             # 固定文字列検索
 
# -z: NULL文字を行区切りとして扱う(マルチライン検索の一種)
grep -Pzo "function.*?\n.*?return" *.js   # 関数定義から return まで
 
# --binary-files: バイナリファイルの扱い
grep --binary-files=text "pattern" binary_file   # バイナリをテキストとして検索
grep -a "pattern" binary_file                     # -a と同等
 
# -T: タブ揃えで出力
grep -Tn "pattern" file.txt          # タブで位置を揃えて表示

3.4 grep + xargs による一括操作

# 検索結果のファイルに対して一括操作
grep -rl "old_function" ./src/ | xargs sed -i 's/old_function/new_function/g'
# → old_function を含むファイルを見つけて、一括置換
 
# 検索結果のファイルをエディタで開く
grep -rl "TODO" ./src/ | xargs code
# → TODO を含むファイルを VS Code で開く
 
# 検索結果を一覧表示
grep -rl "deprecated" ./src/ | xargs ls -la
# → deprecated を含むファイルの詳細情報
 
# NULL区切りを使った安全な一括操作(スペース入りファイル名対応)
grep -rlZ "pattern" . | xargs -0 wc -l
grep -rlZ "old" . | xargs -0 sed -i 's/old/new/g'

4. ripgrep(rg)— モダンな高速検索ツール

4.1 インストールと概要

# インストール
brew install ripgrep               # macOS
sudo apt install ripgrep           # Ubuntu/Debian
sudo pacman -S ripgrep             # Arch Linux
cargo install ripgrep              # Rust (Cargo)
 
# ripgrep の特徴
# - デフォルトで再帰検索
# - .gitignore を自動で尊重
# - Unicode 対応
# - カラー出力がデフォルト
# - 並列処理による高速検索
# - 行番号の自動表示
# - 豊富なファイルタイプフィルタ

4.2 基本的な使い方

# 基本構文: rg [オプション] パターン [パス]
rg "pattern"                       # カレントディレクトリを再帰検索
rg "pattern" src/                  # src/ ディレクトリを検索
rg "pattern" file.txt              # 特定ファイルを検索
 
# 大小文字の制御
rg -i "error"                      # 大小文字無視(ignore case)
rg -s "Error"                      # 大小文字を区別(smart case 無効化)
# デフォルト: スマートケース(パターンが全て小文字なら case-insensitive)
 
# 行番号と列番号
rg -n "pattern"                    # 行番号表示(デフォルトで有効)
rg --column "pattern"              # 列番号も表示
 
# コンテキスト表示
rg -A 3 "error"                    # マッチ行の後3行
rg -B 2 "error"                    # マッチ行の前2行
rg -C 2 "error"                    # マッチ行の前後2行

4.3 ファイルタイプフィルタ

# -t: ファイルタイプで絞り込み
rg "pattern" -t py                 # Python ファイルのみ
rg "pattern" -t js                 # JavaScript ファイルのみ
rg "pattern" -t go                 # Go ファイルのみ
rg "pattern" -t rust               # Rust ファイルのみ
rg "pattern" -t java               # Java ファイルのみ
rg "pattern" -t cpp                # C++ ファイルのみ
rg "pattern" -t html               # HTML ファイルのみ
rg "pattern" -t css                # CSS ファイルのみ
rg "pattern" -t yaml               # YAML ファイルのみ
rg "pattern" -t json               # JSON ファイルのみ
rg "pattern" -t md                 # Markdown ファイルのみ
rg "pattern" -t sh                 # シェルスクリプトのみ
rg "pattern" -t sql                # SQL ファイルのみ
rg "pattern" -t docker             # Dockerfile のみ
rg "pattern" -t make               # Makefile のみ
 
# -T: ファイルタイプを除外
rg "pattern" -T js                 # JavaScript 以外
rg "pattern" -T test               # テストファイル以外
 
# -g: グロブパターンでフィルタ
rg "pattern" -g "*.{js,ts}"        # .js と .ts ファイル
rg "pattern" -g "!*.min.js"        # .min.js を除外
rg "pattern" -g "src/**"           # src/ ディレクトリ以下のみ
rg "pattern" -g "!test/**"         # test/ を除外
 
# 定義済みタイプの一覧
rg --type-list                     # 全ファイルタイプとその拡張子を表示
rg --type-list | grep "python"     # Python タイプの定義を確認
 
# カスタムタイプの定義
rg --type-add "web:*.{html,css,js}" -t web "pattern"   # カスタムタイプで検索

4.4 出力制御

# -l: マッチしたファイル名のみ表示
rg "pattern" -l                    # マッチするファイル名のみ
 
# --files-without-match: マッチしないファイル名を表示
rg "pattern" --files-without-match
 
# -c: ファイルごとのマッチ数をカウント
rg "TODO|FIXME" -c                 # ファイルごとの TODO/FIXME 数
 
# --count-matches: マッチの総数(行単位ではなく出現数)
rg "pattern" --count-matches
 
# -o: マッチ部分のみ表示
rg -o "\d+\.\d+\.\d+" file.txt    # バージョン番号を抽出
 
# --json: JSON 形式で出力(ツール連携用)
rg "pattern" --json                # 検索結果をJSON形式で出力
 
# --vimgrep: Vim の quickfix 形式で出力
rg "pattern" --vimgrep             # ファイル:行:列:マッチ行
 
# --no-heading: ファイル名をグループヘッダーではなく各行に表示
rg --no-heading "pattern"
 
# --heading: ファイル名をグループヘッダーとして表示(デフォルト)
rg --heading "pattern"
 
# -U: マルチラインマッチ
rg -U "function.*\n.*return" -t js  # 複数行にまたがるパターン
 
# -M: マッチ行の最大文字数を制限
rg -M 200 "pattern"                # マッチ行が200文字を超えたら省略
 
# --trim: マッチ行の先頭の空白を除去
rg --trim "pattern"

4.5 隠しファイルと .gitignore

# デフォルトの動作
# - .gitignore を尊重
# - 隠しファイル(.xxx)を除外
# - バイナリファイルを除外
 
# --hidden: 隠しファイルを含める
rg "pattern" --hidden              # .env, .config 等を含めて検索
rg "API_KEY" --hidden              # .env ファイル内の検索
 
# --no-ignore: .gitignore を無視
rg "pattern" --no-ignore           # .gitignore 対象ファイルも検索
rg "pattern" -u                    # --no-ignore の短縮形
 
# -uu: 隠しファイル + .gitignore 無視
rg "pattern" -uu                   # --hidden --no-ignore と同等
 
# -uuu: さらにバイナリファイルも検索
rg "pattern" -uuu                  # 全ファイルを対象(find + grep と同等)
 
# --no-ignore-vcs: VCS の ignore ファイルのみ無視(.gitignore 等)
rg "pattern" --no-ignore-vcs
 
# 特定の ignore ファイルを追加
rg "pattern" --ignore-file .customignore

4.6 rg の置換機能

# -r / --replace: マッチ部分を置換して表示(ファイルは変更しない)
rg "old" -r "new"                  # "old" を "new" に置換して表示
rg "foo(\d+)" -r "bar$1"          # キャプチャグループを使った置換
 
# 実際のファイル置換は sed と組み合わせる
rg -l "old_name" -t py | xargs sed -i 's/old_name/new_name/g'
 
# 置換のプレビュー
rg "old_function" -r "new_function" --passthru
# → マッチしない行も表示し、マッチ行は置換後の状態で表示

4.7 rg の実務パターン集

# --- コード検索 ---
 
# TODO/FIXME/HACK の一括検索
rg "TODO|FIXME|HACK|XXX" -t py -t js -t go
 
# 未使用の import を検索(Python)
rg "^import|^from .* import" -t py --no-heading
 
# console.log の残りを検索(JavaScript)
rg "console\.(log|debug|info|warn|error)" -t js -t ts
 
# デバッグ文の検索(Python)
rg "(print\(|pdb\.set_trace|breakpoint\(\))" -t py
 
# 関数定義の検索
rg "^(def|class) " -t py                    # Python
rg "^(export )?(function|const|class) " -t js  # JavaScript
rg "^func " -t go                            # Go
rg "^(pub )?fn " -t rust                     # Rust
 
# --- ログ分析 ---
 
# HTTPステータスコード別のカウント
rg -o "HTTP/\d\.\d\" (\d{3})" -r '$1' access.log | sort | uniq -c | sort -rn
 
# 特定時間帯のログ
rg "^2026-02-16 1[4-5]:" app.log
 
# エラーログの IP アドレス抽出
rg "ERROR" access.log | rg -o "\d+\.\d+\.\d+\.\d+" | sort -u
 
# --- 設定ファイル ---
 
# 環境変数の使用箇所を検索
rg "process\.env\." -t js -t ts
rg "os\.environ" -t py
rg "os\.Getenv" -t go
 
# ハードコードされた認証情報の検出
rg -i "(password|secret|api.?key|token)\s*[:=]\s*[\"']" --hidden
 
# --- プロジェクト管理 ---
 
# ファイルの行数統計(rg + wc)
rg --files -t py | xargs wc -l | sort -n
 
# 使用ライブラリの検索
rg "^import " -t py --no-filename | sort -u    # Python のインポート一覧
rg "require\(" -t js --no-filename -o | sort -u  # Node.js の require 一覧
 
# 特定の関数の使用箇所
rg "deprecated_function\(" -t py --stats      # --stats でマッチ統計も表示

4.8 rg の設定ファイル

# ~/.ripgreprc に設定を記述
# 環境変数 RIPGREP_CONFIG_PATH で設定ファイルのパスを指定
 
# ~/.ripgreprc の例
cat > ~/.ripgreprc << 'EOF'
# デフォルトでスマートケース
--smart-case
 
# 最大列数
--max-columns=200
 
# 隠しファイルを含める
# --hidden
 
# 特定ディレクトリを常に除外
--glob=!.git/
--glob=!node_modules/
--glob=!target/
--glob=!__pycache__/
--glob=!*.pyc
 
# カスタムタイプの定義
--type-add=web:*.{html,css,js,ts}
EOF
 
# 設定ファイルのパスを環境変数で指定(~/.bashrc に追加)
export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"

5. 他の検索ツール

5.1 ag(The Silver Searcher)

# インストール
brew install the_silver_searcher    # macOS
sudo apt install silversearcher-ag  # Ubuntu/Debian
 
# 基本的な使い方
ag "pattern"                        # 再帰検索(.gitignore 尊重)
ag -i "pattern"                     # 大小文字無視
ag "pattern" -G "\.py$"             # Python ファイルのみ
ag -l "pattern"                     # マッチファイル名のみ
ag --stats "pattern"                # 統計情報付き
 
# rg と ag の比較:
# ag: rg 以前のモダン grep。まだ使われているが、rg の方が高速
# rg: ag の後継として開発。ほぼ全ての面で ag を上回る

5.2 ack

# インストール
brew install ack                    # macOS
sudo apt install ack               # Ubuntu/Debian
 
# 基本的な使い方
ack "pattern"                       # 再帰検索
ack "pattern" --python              # Python ファイルのみ
ack "pattern" --type-set=web:ext:html,css,js  # カスタムタイプ
ack -f --python                     # Python ファイルの一覧
 
# ack は grep の先駆的な代替ツール
# 現在は rg が最も推奨される

5.3 grep / rg / ag / ack の比較

機能greprgagack
速度標準最速高速中速
.gitignore非対応対応対応対応
カラー--colorデフォルトデフォルトデフォルト
Unicode制限あり完全対応部分対応部分対応
PCRE-P (GNU)デフォルト部分対応Perl正規表現
マルチライン制限あり-U非対応非対応
環境標準搭載別途導入別途導入別途導入
置換非対応-r (表示)非対応非対応
並列処理非対応対応対応非対応
推奨: rg を最優先で使用。スクリプトでは POSIX 互換の grep を使用。

6. 実務パターン集(応用編)

6.1 ログ分析ワンライナー

# アクセスログの IP アドレス別アクセス数トップ20
grep -oP "^\d+\.\d+\.\d+\.\d+" access.log | sort | uniq -c | sort -rn | head -20
 
# HTTP ステータスコード分布
awk '{print $9}' access.log | sort | uniq -c | sort -rn
 
# 404 エラーの URL 一覧
grep " 404 " access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20
 
# 特定時間帯のリクエスト数
grep "16/Feb/2026:14:" access.log | wc -l
 
# レスポンスタイムの分析(最終フィールドがレスポンスタイムの場合)
awk '{print $NF}' access.log | sort -n | tail -20    # 遅いリクエスト
 
# エラーレートの計算
total=$(wc -l < access.log)
errors=$(grep -c " [45][0-9][0-9] " access.log)
echo "Error rate: $(echo "scale=2; $errors * 100 / $total" | bc)%"
 
# リアルタイムエラー監視(カラー付き)
tail -f access.log | grep --color=always --line-buffered " [45][0-9][0-9] "

6.2 セキュリティ監査パターン

# ハードコードされた認証情報の検出
rg -i "(password|passwd|pwd)\s*[:=]" --hidden -g "!*.{lock,sum}"
rg -i "api[_-]?key\s*[:=]\s*['\"]" --hidden
rg -i "secret\s*[:=]" --hidden -g "!*.{lock,sum}"
rg "-----BEGIN (RSA |DSA |EC )?PRIVATE KEY-----" --hidden
 
# SQL インジェクションの脆弱性検出
rg "execute\(.*\+.*\)" -t py         # 文字列連結による SQL
rg "query\(.*\$" -t js               # テンプレートリテラルによる SQL
rg "f\".*SELECT.*{" -t py            # f-string による SQL
 
# XSS の脆弱性検出
rg "innerHTML\s*=" -t js -t ts
rg "dangerouslySetInnerHTML" -t js -t ts
rg "v-html=" -t html
 
# 安全でない関数の使用検出
rg "eval\(" -t py -t js              # eval の使用
rg "exec\(" -t py                    # exec の使用
rg "pickle\.loads?" -t py            # pickle の使用

6.3 コードレビュー支援パターン

# デバッグ用コードの残り検出
rg "console\.(log|debug)" -t js -t ts  # JS/TS のデバッグ出力
rg "print\(" -t py -g "!test_*"        # Python の print(テスト除外)
rg "debugger" -t js -t ts              # JS のデバッグブレークポイント
rg "binding\.pry" -t ruby              # Ruby のデバッグ
rg "fmt\.Print" -t go -g "!*_test.go"  # Go の fmt.Print(テスト除外)
 
# TODO/FIXME のサマリー
rg "TODO|FIXME|HACK|XXX|DEPRECATED" --stats -c | sort -t: -k2 -rn
 
# 長い関数の検出(行数ベース)
rg -U "^def \w+.*:\n(.*\n){50,}" -t py --no-heading -l
# → 50行以上の Python 関数を含むファイル
 
# マジックナンバーの検出
rg "(?<![\"'])\b\d{3,}\b(?![\"'])" -t py -g "!test_*" -g "!*constants*"

7. トラブルシューティング

7.1 よくある問題と対処法

# 問題: 特殊文字がパターンとして解釈される
# 対処: -F(固定文字列)を使うか、エスケープする
grep -F "[ERROR]" logfile.txt        # -F で固定文字列として検索
grep "\[ERROR\]" logfile.txt         # エスケープする
rg -F "[ERROR]" logfile.txt          # rg でも -F が使える
 
# 問題: バイナリファイルがマッチする
# 対処: -I オプションでバイナリを無視
grep -rI "pattern" ./               # バイナリファイルを無視
rg "pattern"                        # rg はデフォルトでバイナリを無視
 
# 問題: 大量のマッチで出力が溢れる
# 対処: -m, -l, less を使う
grep -m 10 "pattern" logfile.txt    # 最初の10件で停止
grep -l "pattern" *.log             # ファイル名のみ
grep "pattern" logfile.txt | less   # ページャで閲覧
 
# 問題: macOS の grep で -P(PCRE)が使えない
# 対処: GNU grep をインストールするか、rg を使う
brew install grep                    # ggrep としてインストールされる
ggrep -P "\d+" file.txt             # GNU grep の PCRE
rg "\d+" file.txt                   # rg を使う(推奨)
 
# 問題: UTF-8 のファイルで日本語が検索できない
# 対処: ロケールを確認/設定
export LANG=en_US.UTF-8
grep "日本語" file.txt              # UTF-8 が正しく設定されていれば動作
rg "日本語" file.txt                # rg はUnicode対応
 
# 問題: grep -r が遅い
# 対処: rg を使うか、--include/--exclude-dir を指定
rg "pattern"                         # rg は圧倒的に高速
grep -rn --include="*.py" --exclude-dir=venv "pattern" ./  # grep で絞り込み

7.2 パフォーマンスのヒント

# 1. -F(固定文字列検索)は正規表現より高速
grep -F "exact string" large_file.txt
 
# 2. -m で検索を早期終了
grep -m 1 "pattern" large_file.txt   # 最初の1件で停止
 
# 3. 不要なオプションを避ける
# -i(大小文字無視)は若干遅くなる
# -E(拡張正規表現)は単純パターンでは不要
 
# 4. 検索範囲を限定する
grep -rn --include="*.py" "pattern" ./  # ファイルタイプを限定
grep "pattern" specific_file.txt         # 特定ファイルのみ
 
# 5. rg は grep の 2〜10 倍高速
# 大規模コードベースでは rg を第一選択にする
 
# 6. LC_ALL=C で高速化(ASCII のみの場合)
LC_ALL=C grep "pattern" large_file.txt   # ロケール処理をスキップ

実践演習

演習1: 基本的な実装

以下の要件を満たすコードを実装してください。

要件:

  • 入力データの検証を行うこと
  • エラーハンドリングを適切に実装すること
  • テストコードも作成すること
# 演習1: 基本実装のテンプレート
class Exercise1:
    """基本的な実装パターンの演習"""
 
    def __init__(self):
        self.data = []
 
    def validate_input(self, value):
        """入力値の検証"""
        if value is None:
            raise ValueError("入力値がNoneです")
        return True
 
    def process(self, value):
        """データ処理のメインロジック"""
        self.validate_input(value)
        self.data.append(value)
        return self.data
 
    def get_results(self):
        """処理結果の取得"""
        return {
            'count': len(self.data),
            'data': self.data
        }
 
# テスト
def test_exercise1():
    ex = Exercise1()
    assert ex.process(1) == [1]
    assert ex.process(2) == [1, 2]
    assert ex.get_results()['count'] == 2
 
    try:
        ex.process(None)
        assert False, "例外が発生するべき"
    except ValueError:
        pass
 
    print("全テスト合格!")
 
test_exercise1()

演習2: 応用パターン

基本実装を拡張して、以下の機能を追加してください。

# 演習2: 応用パターン
from typing import List, Dict, Optional
from datetime import datetime
 
class AdvancedExercise:
    """応用パターンの演習"""
 
    def __init__(self, max_size: int = 100):
        self._items: List[Dict] = []
        self._max_size = max_size
        self._created_at = datetime.now()
 
    def add(self, key: str, value: any) -> bool:
        """アイテムの追加(サイズ制限付き)"""
        if len(self._items) >= self._max_size:
            return False
        self._items.append({
            'key': key,
            'value': value,
            'timestamp': datetime.now().isoformat()
        })
        return True
 
    def find(self, key: str) -> Optional[Dict]:
        """キーによる検索"""
        for item in reversed(self._items):
            if item['key'] == key:
                return item
        return None
 
    def remove(self, key: str) -> bool:
        """キーによる削除"""
        for i, item in enumerate(self._items):
            if item['key'] == key:
                self._items.pop(i)
                return True
        return False
 
    def stats(self) -> Dict:
        """統計情報"""
        return {
            'total_items': len(self._items),
            'max_size': self._max_size,
            'usage_percent': len(self._items) / self._max_size * 100,
            'uptime': str(datetime.now() - self._created_at)
        }
 
# テスト
def test_advanced():
    ex = AdvancedExercise(max_size=3)
    assert ex.add("a", 1) == True
    assert ex.add("b", 2) == True
    assert ex.add("c", 3) == True
    assert ex.add("d", 4) == False  # サイズ制限
    assert ex.find("b")['value'] == 2
    assert ex.remove("b") == True
    assert ex.find("b") is None
    stats = ex.stats()
    assert stats['total_items'] == 2
    print("応用テスト全合格!")
 
test_advanced()

演習3: パフォーマンス最適化

以下のコードのパフォーマンスを改善してください。

# 演習3: パフォーマンス最適化
import time
from functools import lru_cache
 
# 最適化前(O(n^2))
def slow_search(data: list, target: int) -> int:
    """非効率な検索"""
    for i in range(len(data)):
        for j in range(i + 1, len(data)):
            if data[i] + data[j] == target:
                return (i, j)
    return (-1, -1)
 
# 最適化後(O(n))
def fast_search(data: list, target: int) -> tuple:
    """ハッシュマップを使った効率的な検索"""
    seen = {}
    for i, num in enumerate(data):
        complement = target - num
        if complement in seen:
            return (seen[complement], i)
        seen[num] = i
    return (-1, -1)
 
# ベンチマーク
def benchmark():
    import random
    data = list(range(5000))
    random.shuffle(data)
    target = data[100] + data[4000]
 
    start = time.time()
    result1 = slow_search(data, target)
    slow_time = time.time() - start
 
    start = time.time()
    result2 = fast_search(data, target)
    fast_time = time.time() - start
 
    print(f"非効率版: {slow_time:.4f}秒")
    print(f"効率版:   {fast_time:.6f}秒")
    print(f"高速化率: {slow_time/fast_time:.0f}倍")
 
benchmark()

ポイント:

  • アルゴリズムの計算量を意識する
  • 適切なデータ構造を選択する
  • ベンチマークで効果を測定する

設計判断ガイド

選択基準マトリクス

技術選択を行う際の判断基準を以下にまとめます。

判断基準 重視する場合 妥協できる場合
パフォーマンス リアルタイム処理、大規模データ 管理画面、バッチ処理
保守性 長期運用、チーム開発 プロトタイプ、短期プロジェクト
スケーラビリティ 成長が見込まれるサービス 社内ツール、固定ユーザー
セキュリティ 個人情報、金融データ 公開データ、社内利用
開発速度 MVP、市場投入スピード 品質重視、ミッションクリティカル

アーキテクチャパターンの選択

アーキテクチャ選択フロー
① チーム規模は?
├─ 小規模(1-5人)→ モノリス
└─ 大規模(10人+)→ ②へ
② デプロイ頻度は?
├─ 週1回以下 → モノリス + モジュール分割
└─ 毎日/複数回 → ③へ
③ チーム間の独立性は?
├─ 高い → マイクロサービス
└─ 中程度 → モジュラーモノリス

トレードオフの分析

技術的な判断には必ずトレードオフが伴います。以下の観点で分析を行いましょう:

1. 短期 vs 長期のコスト

  • 短期的に速い方法が長期的には技術的負債になることがある
  • 逆に、過剰な設計は短期的なコストが高く、プロジェクトの遅延を招く

2. 一貫性 vs 柔軟性

  • 統一された技術スタックは学習コストが低い
  • 多様な技術の採用は適材適所が可能だが、運用コストが増加

3. 抽象化のレベル

  • 高い抽象化は再利用性が高いが、デバッグが困難になる場合がある
  • 低い抽象化は直感的だが、コードの重複が発生しやすい
# 設計判断の記録テンプレート
class ArchitectureDecisionRecord:
    """ADR (Architecture Decision Record) の作成"""
 
    def __init__(self, title: str):
        self.title = title
        self.context = ""
        self.decision = ""
        self.consequences = []
        self.alternatives = []
 
    def set_context(self, context: str):
        """背景と課題の記述"""
        self.context = context
        return self
 
    def set_decision(self, decision: str):
        """決定内容の記述"""
        self.decision = decision
        return self
 
    def add_consequence(self, consequence: str, positive: bool = True):
        """結果の追加"""
        self.consequences.append({
            'description': consequence,
            'type': 'positive' if positive else 'negative'
        })
        return self
 
    def add_alternative(self, name: str, reason_rejected: str):
        """却下した代替案の追加"""
        self.alternatives.append({
            'name': name,
            'reason_rejected': reason_rejected
        })
        return self
 
    def to_markdown(self) -> str:
        """Markdown形式で出力"""
        md = f"# ADR: {self.title}\n\n"
        md += f"## 背景\n{self.context}\n\n"
        md += f"## 決定\n{self.decision}\n\n"
        md += "## 結果\n"
        for c in self.consequences:
            icon = "✅" if c['type'] == 'positive' else "⚠️"
            md += f"- {icon} {c['description']}\n"
        md += "\n## 却下した代替案\n"
        for a in self.alternatives:
            md += f"- **{a['name']}**: {a['reason_rejected']}\n"
        return md

チーム開発での活用

コードレビューのチェックリスト

このトピックに関連するコードレビューで確認すべきポイント:

  • 命名規則が一貫しているか
  • エラーハンドリングが適切か
  • テストカバレッジは十分か
  • パフォーマンスへの影響はないか
  • セキュリティ上の問題はないか
  • ドキュメントは更新されているか

ナレッジ共有のベストプラクティス

方法 頻度 対象 効果
ペアプログラミング 随時 複雑なタスク 即時のフィードバック
テックトーク 週1回 チーム全体 知識の水平展開
ADR (設計記録) 都度 将来のメンバー 意思決定の透明性
振り返り 2週間ごと チーム全体 継続的改善
モブプログラミング 月1回 重要な設計 合意形成

技術的負債の管理

優先度マトリクス:

        影響度 高
          │
計画即座
的に
対応対応
記録次の
のみSprint
│
        影響度 低
    発生頻度 低  発生頻度 高

セキュリティの考慮事項

一般的な脆弱性と対策

脆弱性 リスクレベル 対策 検出方法
インジェクション攻撃 入力値のバリデーション・パラメータ化クエリ SAST/DAST
認証の不備 多要素認証・セッション管理の強化 ペネトレーションテスト
機密データの露出 暗号化・アクセス制御 セキュリティ監査
設定の不備 セキュリティヘッダー・最小権限の原則 構成スキャン
ログの不足 構造化ログ・監査証跡 ログ分析

セキュアコーディングのベストプラクティス

# セキュアコーディング例
import hashlib
import secrets
import hmac
from typing import Optional
 
class SecurityUtils:
    """セキュリティユーティリティ"""
 
    @staticmethod
    def generate_token(length: int = 32) -> str:
        """暗号学的に安全なトークン生成"""
        return secrets.token_urlsafe(length)
 
    @staticmethod
    def hash_password(password: str, salt: Optional[str] = None) -> tuple:
        """パスワードのハッシュ化"""
        if salt is None:
            salt = secrets.token_hex(16)
        hashed = hashlib.pbkdf2_hmac(
            'sha256',
            password.encode('utf-8'),
            salt.encode('utf-8'),
            iterations=100000
        )
        return hashed.hex(), salt
 
    @staticmethod
    def verify_password(password: str, hashed: str, salt: str) -> bool:
        """パスワードの検証"""
        new_hash, _ = SecurityUtils.hash_password(password, salt)
        return hmac.compare_digest(new_hash, hashed)
 
    @staticmethod
    def sanitize_input(value: str) -> str:
        """入力値のサニタイズ"""
        dangerous_chars = ['<', '>', '"', "'", '&', '\\']
        result = value
        for char in dangerous_chars:
            result = result.replace(char, '')
        return result.strip()
 
# 使用例
token = SecurityUtils.generate_token()
hashed, salt = SecurityUtils.hash_password("my_password")
is_valid = SecurityUtils.verify_password("my_password", hashed, salt)

セキュリティチェックリスト

  • 全ての入力値がバリデーションされている
  • 機密情報がログに出力されていない
  • HTTPS が強制されている
  • CORS ポリシーが適切に設定されている
  • 依存パッケージの脆弱性スキャンが実施されている
  • エラーメッセージに内部情報が含まれていない

FAQ

Q1: このトピックを学ぶ上で最も重要なポイントは何ですか?

実践的な経験を積むことが最も重要です。理論だけでなく、実際にコードを書いて動作を確認することで理解が深まります。

Q2: 初心者がよく陥る間違いは何ですか?

基礎を飛ばして応用に進むことです。このガイドで説明している基本概念をしっかり理解してから、次のステップに進むことをお勧めします。

Q3: 実務ではどのように活用されていますか?

このトピックの知識は、日常的な開発業務で頻繁に活用されます。特にコードレビューやアーキテクチャ設計の際に重要になります。


まとめ

オプション / ツール 意味
grep -i 大小文字無視
grep -r / -R 再帰検索
grep -n 行番号表示
grep -l / -L マッチ/非マッチファイル名
grep -v 逆マッチ
grep -w 単語完全一致
grep -E 拡張正規表現
grep -F 固定文字列(正規表現無効)
grep -P Perl 互換正規表現
grep -o マッチ部分のみ表示
grep -c マッチ行数カウント
grep -A/-B/-C N 前後のコンテキスト
grep -q 終了コードのみ(出力なし)
grep --include 対象ファイルの絞り込み
grep --exclude-dir ディレクトリの除外
rg (ripgrep) 高速再帰検索(.gitignore 尊重)
rg -t TYPE ファイルタイプフィルタ
rg -g GLOB グロブパターンフィルタ
rg --hidden 隠しファイルを含める
rg -U マルチラインマッチ

12. grep / rg のパフォーマンスチューニング

12.1 検索速度の最適化

# grep の高速化テクニック
 
# 1. 固定文字列検索(-F)は正規表現より高速
grep -F "exact string" file.txt              # 正規表現解析をスキップ
grep -F "error" large_log.txt                # 単純な文字列検索に最適
fgrep "pattern" file.txt                     # -F のエイリアス(非推奨だが利用可)
 
# 2. ロケール設定で高速化
LC_ALL=C grep "pattern" file.txt             # Cロケール(ASCII前提)で大幅に高速化
# → UTF-8ロケールの場合、文字クラスの処理が重い
# → 英数字のみの検索なら LC_ALL=C が効果的
 
# 3. 不要なオプションを避ける
grep -c "pattern" file.txt                   # カウントだけなら -c(行全体を出力しない)
grep -q "pattern" file.txt                   # 存在確認だけなら -q(最初のマッチで終了)
grep -l "pattern" *.log                      # ファイル名だけなら -l(全行スキャン不要)
grep -m 1 "pattern" file.txt                 # 最初のマッチだけなら -m 1(早期終了)
 
# 4. バッファリングの制御
grep --line-buffered "pattern" file.txt      # 行バッファリング(リアルタイム出力)
# → パイプラインで使用する場合に有用
 
# 5. 並列検索
grep -r "pattern" /path --include="*.py" &   # バックグラウンドで実行
# GNU parallel を使った並列検索
find . -name "*.log" | parallel -j4 grep -l "ERROR" {}
 
# ripgrep の高速化テクニック
# rg はデフォルトで最適化されているが、さらに調整可能
 
# スレッド数の制御
rg -j 4 "pattern" /large/directory           # 4スレッドで検索
rg -j 1 "pattern" file.txt                   # シングルスレッド(小ファイル向け)
 
# メモリマップの制御
rg --mmap "pattern" huge_file.txt            # メモリマップを強制使用
rg --no-mmap "pattern" /nfs/share/           # メモリマップを無効化(NFS等)
 
# バイナリファイルのスキップ
rg --no-binary "pattern" /mixed/content/     # バイナリファイルを完全スキップ
 
# エンコーディング指定
rg -E shift-jis "パターン" legacy_file.txt   # 文字コード指定
rg -E euc-jp "検索語" old_data.txt

12.2 大規模コードベースでの検索戦略

# プロジェクト全体の検索を効率化
 
# 1. .gitignore を活用(rg はデフォルトで尊重)
rg "TODO" .                                   # node_modules, .git 等は自動除外
 
# 2. 検索対象を絞り込む
rg -t py "import" .                           # Python ファイルのみ
rg -g "!tests/" "function" .                  # テストディレクトリを除外
rg -g "*.{ts,tsx}" "useState" .               # TypeScript ファイルのみ
 
# 3. 事前フィルタリング
# よく検索するパターンをエイリアスに登録
alias rgpy='rg -t py'
alias rgjs='rg -t js -t ts'
alias rgerr='rg -i "error|exception|fail"'
alias rgtodo='rg "TODO|FIXME|HACK|XXX"'
 
# 4. 検索結果のキャッシュ(頻繁に実行する場合)
rg -l "pattern" > /tmp/matched_files.txt
cat /tmp/matched_files.txt | xargs rg "another_pattern"
 
# 5. インクリメンタル検索
# fzf と組み合わせた対話的検索
rg --line-number --no-heading "." | fzf --preview 'echo {} | cut -d: -f1-2 | xargs -I{} sh -c "head -n \$(echo {} | cut -d: -f2) \$(echo {} | cut -d: -f1) | tail -5"'
 
# grep / rg と IDE の検索の使い分け
# - 単純な文字列検索: rg(最速)
# - 構文を考慮した検索: IDE(AST ベース)
# - 正規表現の複雑な検索: rg -P(PCRE2)
# - 対話的な絞り込み: rg | fzf

13. 実務シナリオ別の総合レシピ

13.1 インシデント対応での grep/rg 活用

# 障害発生時の迅速なログ調査
 
# 1. エラーの初回発生時刻を特定
rg -m 1 "OutOfMemoryError" /var/log/app/*.log
grep -rn -m 1 "Connection refused" /var/log/
 
# 2. エラー前後のコンテキストを確認
rg -C 10 "FATAL" /var/log/app/app.log | head -50
 
# 3. エラーの頻度を時系列で確認
rg "ERROR" app.log | rg -o "^\d{4}-\d{2}-\d{2} \d{2}:" | sort | uniq -c
 
# 4. 特定時間帯のログを抽出
rg "^2024-01-15 1[4-6]:" app.log                # 14:00-16:59 のログ
grep "^2024-01-15 15:3[0-9]:" app.log            # 15:30-15:39 のログ
 
# 5. 複数サーバーのログを同時検索
for host in web01 web02 web03; do
  echo "=== $host ==="
  ssh "$host" "rg 'ERROR' /var/log/app/app.log | tail -5"
done
 
# 6. スタックトレースの抽出
rg -U "Exception.*\n(\s+at .*\n)+" app.log       # マルチラインマッチ
grep -A 20 "Exception" app.log | grep -B 1 "^$"  # 空行までのスタックトレース
 
# 7. 影響を受けたユーザーの特定
rg "ERROR.*user_id=(\w+)" -o -r '$1' app.log | sort -u
 
# 8. エラー発生パターンの分析
rg -o "ERROR \[([^\]]+)\]" -r '$1' app.log | sort | uniq -c | sort -rn | head -20

13.2 コードレビューでの grep/rg 活用

# コードの品質チェック
 
# 1. ハードコードされた値の検出
rg -n "localhost|127\.0\.0\.1|192\.168\." --type-not test src/
rg -n "password\s*=\s*[\"'][^\"']+[\"']" src/
 
# 2. デバッグコードの残存チェック
rg -n "console\.(log|debug|warn)|print\(|debugger|binding\.pry" src/
rg -n "TODO|FIXME|HACK|XXX|TEMP" src/ --stats
 
# 3. 未使用のインポート検出(簡易版)
for import in $(rg -o "^import \{ (\w+)" -r '$1' src/index.ts); do
  count=$(rg -c "\b$import\b" src/index.ts)
  if [ "$count" -le 1 ]; then
    echo "Possibly unused: $import"
  fi
done
 
# 4. API エンドポイントの一覧抽出
rg -n "(@(Get|Post|Put|Delete|Patch)Mapping|@RequestMapping)" --type java src/
rg -n "router\.(get|post|put|delete|patch)\(" --type js src/
rg -n "@app\.(route|get|post|put|delete)" --type py src/
 
# 5. SQL インジェクションの可能性チェック
rg -n "execute\(.*\+.*\)|execute\(.*%s.*%|execute\(.*\{.*\}.*\.format" --type py src/
rg -n "query\(.*\+.*\)|query\(.*\$\{" --type js src/
 
# 6. 例外処理の確認
rg -n "except:|catch\s*\(" --type py --type java --type js src/ | rg -v "except Exception|catch \(Error"
 
# 7. マジックナンバーの検出
rg -n "(?<!=\s*)\b(0|1)\b(?!\s*[;,\)])" --type java src/ | rg -v "//|/\*|\*/"

13.3 セキュリティ監査での grep/rg 活用

# 包括的なセキュリティスキャン
 
# 1. 機密情報の漏洩チェック
rg -in "(api[_-]?key|secret[_-]?key|access[_-]?token|private[_-]?key)\s*[=:]\s*[\"']?\w+" .
rg -in "BEGIN (RSA |DSA |EC |OPENSSH )?PRIVATE KEY" .
rg -in "(password|passwd|pwd)\s*[=:]\s*[\"'][^\"']{4,}" .
 
# 2. AWS 認証情報の検出
rg "AKIA[0-9A-Z]{16}" .                         # AWS Access Key ID
rg "[0-9a-zA-Z/+]{40}" . | rg -v "test|example"  # AWS Secret Key(要確認)
 
# 3. 脆弱な暗号化の使用
rg -in "md5|sha1(?!sum)|des[^ign]|rc4" --type py --type java --type js .
rg -in "eval\s*\(|exec\s*\(|system\s*\(" --type py --type rb .
 
# 4. CORS 設定の確認
rg -in "Access-Control-Allow-Origin.*\*" .
rg -in "cors.*origin.*\*|allowAllOrigins" .
 
# 5. ファイルパーミッションの確認(設定ファイル内)
rg -in "chmod\s+777|chmod\s+666|umask\s+000" .
 
# 6. 入力バリデーションの欠如
rg -n "request\.(params|query|body)\.\w+" --type js . | rg -v "validate|sanitize|escape"

次に読むべきガイド


参考文献

  1. Barrett, D. "Efficient Linux at the Command Line." Ch.5, O'Reilly, 2022.
  2. Friedl, J. "Mastering Regular Expressions." 3rd Ed, O'Reilly, 2006.
  3. GNU Grep Manual. https://www.gnu.org/software/grep/manual/
  4. ripgrep GitHub Repository. https://github.com/BurntSushi/ripgrep
  5. ripgrep User Guide. https://github.com/BurntSushi/ripgrep/blob/master/GUIDE.md