行範囲のいろいろな指定方法

いろいろな行単位の操作対象の指定方法

概要

Vi(JVim)ではコマンドモード中に : (コロン) を押して, 画面の一番下の行で打つコマンド が結構多く, その多くは「 Exコマンド 」と呼ばれます. ここでは, この「Exコマンド」での操作対象となる行や範囲の指定方法について書きます

Exコマンドとは

普段は,「カーソルのある行を削除」する時には

dd

と打つと思いますが

:d

と打っても同じだということを知っている人も多いと思います
この時の : (コロン)を打ってから入力するコマンドの多くは「Exコマンド」と 呼ばれます

何故,同じ「削除」なのに,こういった指定方法が用意されているのかについては ここでは詳しく触れませんが, この書き方を使うと dd とは一味違った感覚で テキストの編集ができます. たとえば :6d とすれば, 現在のカーソル位置や表示位置とは全く関係なく , 6行目 を削除できます. このように Exコマンドの多くは「現在何が表示されているかなんて 全然関係なく」

:(操作対象)(コマンド) (オプションとか)

という形式で,ファイルの大抵の編集操作を行うことが可能です

このように,表示と関係なくファイル内容に変更を加えることができると 表示を更新しないので, 処理が高速になり,また,(操作対象)に検索文や正規表現を 書くなどの抽象的な対象指定もできるようになります
知っている人なら分かるでしょうけど, ストリームエディタ"sed" に似た感覚で文章に 変更を加えることができます

いくつか操作対象とコマンドの例を書くと

:5,10ya b

…これは 5行目から10行目全体を Yankして名前つきバッファ"b"に入れます
Exコマンド ya というのが yank の意味です

:g!/abc/nu

ならば "abc"という文字列を全く含まない行を, すべて行番号つきで表示します
Exコマンド nu number の略. g!/abc の部分が 操作対象の指定 となっています

この最後の例の g!/ (文字列) という操作対象指定方法を覚えたのであれば 「スクリプトのコメントが書かれている行だけを見たい」時に

:g/#/p

とか

:g/#/nu

とすれば,通常の検索のようにカーソルを移動させずに,grepのように一覧できます
さらに, :g!/#/d として, 実際にコメントが含まれている行だけを残したりもできます
これを使えばファイル中にいくつかある特定の文字列のある行をわざわざ「見に行かなくても」 grepのように簡単な一覧形式で見たり, 抽象的な条件に基づいてコマンドを適用することが できます

このように,Exコマンドを使うと, ちょっと複雑な代わりに 派手な処理をコマンド 一発で処理 することができます

どうですか ? ちょっと複雑な感じもしますが,全部覚えていなくても,使い勝手は かなり違ってくると思います. ぜひ以下も読んで見て下さい

いろいろな行の指定方法

解説と例を出しながら 次々と紹介します
例では,いろいろなコマンドも出すようにしてみました
これらの例を元にして応用して使って下さい


まず, 「数字」は,行番号 とみなされます

:3,6left 9

だと,三行目から六行目までの範囲の行にインデントを9文字分つけます


. (ピリオド)は,「 現在カーソルのある行 」という意味です

:70,.nu

だと, 70行目から現在カーソルのある行までを行番号つきで表示します


$ は「 ファイルの最後の行 」という意味です

:.,$ce

だと,カーソルのある行からファイルの最後までをセンタリングします


範囲を指定する時の起点となる行が「現在カーソルのある行」であれば . (ピリオド)は 省略できます

:,$d g

だと,現在行からファイル最後までを削除して名前付きバッファ"g"に入れます


+ (プラス)は,「その行の 次の行 」という意味です

:3,.+#

だと,三行目から"現在行の次の行"までを行番号つきで表示します


- (マイナス)は,「その行の 前の行 」という意味です

:-,+ya e

だと,"現在行の前の行"から"現在行の次の行"まで,つまり"現在行の前後を含む 3行" を Yankして名前つきバッファ "e"に格納します


+ - には 数字を付けて,行番号を増減できます

:.+4,$-6w !wc

だと,"現在行の四行後ろ"から"ファイルの最後よりも6行手前"までの部分を 外部のunixコマンドである"wc"の入力として渡して 行/単語/文字数を数えさせます


% は「 ファイルのすべての行 」という意味です

:%!sort -nr

だと, ファイル全体を外部のコマンド"sort -nr"に通した出力と置き換えます
わざわざファイルの先頭や末尾にカーソルを移動させなくてもファイル全体が 指定できるので, 非常に良く使う記号です


/文字列 は「"文字列"を後ろに 検索していって最初に見つかった行 」です

:/abc/ma a

だと,"abc"という文字列が最初に見つかった行に "a"というマークをつけます


?文字列 は「"文字列"を 前方に検索 していって最初に見つかった行」です

:?abc,$join

だと,前方に"abc"文字列を含む行からファイルの最後までを一行につなげます


'(文字) は「(文字)で マークされた行 」です

:'a,'b move $

だと,「文字"a"でマークされた行から 文字"b"でマークされた行」の領域を ファイルの末尾に移動させます


範囲の始点と終点の指定の区切りには , の他に ; も使えます

:4,+2

だと,四行目から「現在行の二行先の行」まで,という意味ですが

:4;+2

だと,四行目から六行目まで,という意味です
つまり区切りに ; を使った場合は 範囲の 始点から計算される ようになります

:.-2;+4 copy $

だと,現在行の二行前からから四行分をファイルの末尾にコピーします

:1;/abc/l

などとした時の "abc"文字検索も「ファイルの一行目から」スタートしますから このコマンドは「ファイルの一行目から, "abc"という文字が見つかる行までの改行文字 やタブ文字を可視化して表示」します

実際に範囲指定をするには

行範囲を行番号で指定したくても「行番号や行数をいちいち調べるのは面倒」と 思うかも知れませんが,多くの場合は簡単です

入力例 1

5:

と入力してみて下さい,すると自動的に :.,.+4 という表示に変わります
これは「カーソルから5行分」の意味ですから, この後に,お好みのコマンドを 打って使えます

入力例 2

5!(Return)

または 5!! と入力してみて下さい, すると自動的に行番号の範囲が書かれて :20,25! などという表示になります. 文字"!"は「外部のフィルタ プログラムに通す」処理ですから, この後ろにプログラム名を書けば 簡単に5行分を処理できます

入力例 3

まず V …つまり, 大文字の V を打ってから カーソルを自由に移動させると V を打った場所とカーソル位置に挟まれた範囲が反転表示に なります(Visualモード). 「この範囲にしよう」と決めたら
: または ! を打つと, その瞬間に行範囲指定つきの行が画面最下行に 出ます. あとはお好みでどうぞ

入力例 4

まず ! を打ってから, カーソル移動コマンドで一度だけの移動を試みます
すると, カーソルが移動するかわりに :200,224! などと, 行範囲の指定が 書かれます. この範囲は通常のコマンドで範囲を指定する時のような「カーソル元位置 から移動予定後の範囲」を行番号化したものです. 範囲の最後には自動的に ! マーク が書かれていますが, バックスペースで削除できる ので,任意のExコマンドが 打てます


このように,行番号を直接調べなくても済むような機能があります

それでも行番号が知りたいという時は set ruler のように rulerオプション を設定していれば,画面最下に,常時カーソル位置が表示されるし, set number していれば,常に行番号が表示されたまま編集できます
あるいは :b とか CONT-G で 現在のファイルとカーソル位置の情報が表示されます

Exコマンド行の編集と中断

: を押してから範囲やいろいろな文字を入力した内容は, カーソル移動(矢印キー)で 編集が可能です. もし,Exコマンド行を書いていて打ち間違いした場合は 矢印キーの左右 で,この行内を移動できます. 移動してからバックスペースなどで 文字を削除したり挿入などの編集操作ができるのです. この時だけは,JVimには珍しく, ( h j k l キーじゃなくって)カーソル(矢印キーの左右)を使う操作となります

矢印(カーソル移動)キーなんて絶対使いたくないという人は 適当なキーにmapして 使うと良いでしょう. ちなみに私の場合は

cmap ^B (左矢印キー)
cmap ^F (右矢印キー)
cnoremap ^A ^B

のような行を設定に入れてあるので(すべて制御キー) ちょっとEmacsっぽい操作で コマンド行を編集できるようになってます

また,もし Exコマンド行を途中まで打ってから「やっぱりやめたい」と思った場合 は わざわざバックスペースを連打しなくても Esc ダブルクリックのように2回連打 するか,あるいは CONT-C で, カーソル位置が戻り,何事も無かったかのように復帰できます

過去に実行したExコマンドの再実行

全く同じ Exコマンドを再び実行したい場合は,わざわざ指定を再び書かなくても : だけを打ってから

CONT-P

を押すごとに, 直前,2回前,3回前,4回前…という具合に過去に実行したコマンドを 呼び戻す ことができます. (Return) を押せば, 表示されているコマンド を直接に再実行できるというわけです. 呼び戻して表示させてから編集修正して使っても 良いので,似たような範囲や処理の時にも便利ですね

"g" ( global ) は超便利

:g(条件)(コマンド)

のような形式で,条件を満たすすべての行に対してコマンドを実行できます. たとえば

:g/^#/d

では,行頭に"#"文字があるすべての行を削除します. 逆に

:g!(条件)(コマンド)

とすると, 条件を満たさないすべての行を対象とします

:v(条件)(コマンド)

も "g!"と 全く同義です. さらに

:(範囲)g(条件)(コマンド)

のように, 特定の範囲内の条件を満たす行だけにコマンドを適用できます. たとえば :40,60g!/abcd/left なら「40行から60行の間で,文字列"abcd"を含まない行」の インデントを削除します

使用例あれこれ

以下は自由に思いつく使用例を書きます
応用の際のヒントになるかと思います


:g/#/copy $

だと, # の含まれる行すべてをファイルの末尾にコピーします
何かの特定の文字が含まれる行だけの一覧をファイル末尾や先頭に作れますね


:g/^#/>

だと,先頭に"#"のある行すべてに一段階のインデントをつけます. ただし, smartindent オプションが設定されている場合は 行頭の"#"文字の行には シフト操作が働かないので無効になりますが


:-r filename

は,単なるファイルの読み込みですが, r の直前にも場所の指定として 任意の記法が使えます. この例だと「現在行の上に」読み込みます


:0r!which ruby

だと,外部のコマンド "which ruby"の結果をファイルの先頭に読み込んで書きます
スクリプト言語などの先頭 #! で始まる行を作る時に,コマンドのパスごと書けます
行番号には本当はゼロは無いのですが, 読み込み時にゼロを書くと,ファイルの先頭に 読み込まれます


:/start/,/end/s/old/new/g

だと, "start"という文字が含まれる行から "end"という文字がある行までの範囲内に あるすべての"old"という文字列を"new"に置き換えます
対象範囲内だけに対して一括置換ができるというわけです


:g/moji/s/old/new/g

だと, 文字列"moji"が含まれる行にある"old"文字列を"new"に置換します
この程度なら,"sed"を呼び出すこともないですね
ついでに,後ろに c をつけて

:g/moji/s/old/new/gc

のようにすると, ひとつづつ確認しながら置換できます . ccheck の意味です


:-,+t.-2

現在の行の一つ前からひとつ後の(合計3行)を現在の行の2行手前にコピー


:/end/-3pu h

文字列"end"を含む行の三行前に 名前つきバッファ"h"の内容を書き出す


:/moji/=

"moji"のある最初の行番号を表示


最後に… :5,30 などと範囲だけを書くと 範囲の終わりの行に 移動します. (あまり意味は無いですが)


前項目, 「インデントとタブ関連のコマンド」へ

目次へ

次項目, 「外部のフィルタプログラムの利用」へ