条件に合う行だけ処理する
「TODO と書いてある行だけ全部消したい」「ログ行だけ書き換えたい」。こういう「条件に合う行だけ」の処理をまとめて行うのがグローバルコマンドです。置換が「文字列を探して直す」なら、こちらは「行を探して処理する」道具です。
:s との違い
:%s は「文字列を探して置き換える」もので、対象は文字列です。:g は「行を探して、その行に対してコマンドを実行する」もので、対象は行です。
だから :g/debug/d は「debug を含む行を消す」になります。:%s/debug// だと debug という文字だけが消えて、行そのものは空行として残ります。消したいのが行なのか文字なのかで使い分けます。
組み合わせると効く
本物のVimでは、実行するコマンドに normal を指定して普通のキー操作も流せます。:g/TODO/normal A ; のように書くと、TODO を含む行すべての末尾に文字を足せます(この練習ページでは d と s だけを扱っています)。
範囲を絞ることもできて、:1,20g/foo/d なら1行目から20行目までが対象です。何も書かなければファイル全体が対象になります。
実行する前に確かめる
対象が広いので、間違えると一気に消えます。不安なときは先に / で同じパターンを検索して、どの行に当たるかを目で確かめてから実行すると安全です。
実行してしまっても u で元に戻せます。グローバルコマンド1回ぶんがまとめて1つの変更として扱われるので、u を1回押せば全部戻ります。
:v は条件を裏返す
:v は :g! の別名で、パターンに一致しない行を対象にします。:v/^#/d なら、# で始まらない行、つまりコメント以外を全部消します。
ログから特定の種類の行だけを残したいときは、残したいものを :v で指定するほうが短く書けます。消したいものを列挙するか、残したいものを1つ指定するかで選んでください。
行を消すだけでなく集められる
実行するコマンドは d や s だけではありません。:g/ERROR/t$ と書くと、一致した行をファイルの末尾に複製できます。:g/ERROR/y A なら、一致した行をレジスタ A に集められます。
大文字のレジスタが追記になる性質と組み合わせると、散らばった行を1か所に集めてから別のファイルへ貼る、という作業が2ステップで終わります。ログの調査でよく使われる形です。
先に印を付けてから実行している
:g は、まず条件に一致する行すべてに内部で印を付け、そのあとで印の付いた行に対してコマンドを実行します。2段階になっているので、実行中に行が増減しても対象がずれません。
この仕組みのおかげで :g/foo/d は行を消しながらでも取りこぼしません。1行ずつ上から処理していたら、消したぶんだけ行番号がずれて飛ばしてしまうところです。
このレッスンで扱うキー
| キー | 動き |
|---|---|
| :g | 一致する行だけに実行 |
| :v | 一致しない行だけに実行 |
| d | 対象の行を削除 |
| s | 対象の行を置換 |