はじめに:不格好なパイプ地獄と自己嫌悪
APIのレスポンス(JSON風テキスト)やHTMLのソースコードから、「id="12345" の 12345 の部分だけを取り出したい」。
そんな時、昔の私はこんな「不格好なワンライナー」を量産していました。
# 1. まず grep で行を出す
# 2. cut とかで不要な前を取り除く
# 3. sed で不要な後ろを取り除く
$ grep 'id="' data.txt | cut -d'"' -f2
「動けばいい」とはいえ、後から見返すと何をしているか全く分からないパイプ地獄。フォーマットが少し変わった瞬間に盛大にぶっ壊れる脆さ。
「もっとスマートに、欲しい文字列の部分だけ をピンポイントで引っこ抜けないのか…?」
実は、grep にはそれを1発のコマンドで実現する「黒魔術(高度な正規表現)」が隠されていました。
それが -oP の組み合わせ です。
技術解説:不要な部分を削ぎ落とす「刀」と、最強の「目」
普通の grep は「行全体」を出力しますが、これを「マッチした部分だけ」に絞るのが -o(Only matching)オプションです。
しかし、ただ -o を使うだけでは「検索キーワードそのもの」しか出力されないため、あまり意味がありません。
ここで最強の相棒となるのが、-P(Perl-compatible regular expressions:Perl互換正規表現)です。この -P を使うことで、正規表現の最高峰である「肯定先読み/後読み」という黒魔術が使えるようになります。
黒魔術の呪文:「◯◯の後ろ」かつ「△△の前」だけを取り出す
例として、User ID is: 98765, active: true という文字列から 98765 の数字部分だけを抜き出したいとします。
ここで使うのが 後読み (?<=...)(〜の直後にある)と、先読み (?=...)(〜の直前にある)です。
# -o: マッチした部分だけ出力
# -P: Perl互換正規表現を有効化
$ echo "User ID is: 98765, active: true" | grep -oP '(?<=User ID is: )\d+(?=,)'
出力結果:
98765
図解:先読み・後読みの仕組み
この正規表現は、以下のように解釈されます。
-
(?<=User ID is: )= 「User ID is: 」という文字の後ろにある… -
\d+= 連続した数字(これが本当に抽出したい中身) -
(?=,)= かつ、,(カンマ)の前にあるもの
先読みと後読みの部分は**「条件としてチェックするが、抽出(出力)結果には含めない」**という特殊な働きをします。
だから-oと組み合わせることで、真ん中の「欲しい部分」だけが綺麗にポロッと落ちてくるのです。
伏線回収と読後感:ワンライナーの芸術家へ
この -oP の黒魔術(先読み・後読み)をマスターして以降、私の書くシェルスクリプトから cut や sed が幾重にも連なる不恰好なパイプ処理は一掃されました。
どのような複雑なログフォーマットからでも、前後を条件で挟み撃ちにするだけで、目的の値だけをスマートに、かつ堅牢に抽出できるようになったのです。
「ただの文字検索ツール」だと思っていた grep が、実は最強の「テキスト抽出マシーン」だったと気づいた時の衝撃。
明日から、文字列のパースで cut を打ちそうになったら、一度手を止めて grep -oP の黒魔術を唱えてみてください。ワンライナーが一段階上の、芸術的な美しさに到達しますよ。