私はよく耳にするヴィム、長所と短所の両方があります。開発者として、他のどのエディターよりも Vim の方が速く作業できるように思えます。私はいくつかの基本的な作業に Vim を使用していますが、 Vim を使用すると生産性がせいぜい 10 倍低下します。
速度について話すときに気にする必要があるのは、次の 2 つの点だけです (あまり気にしていないかもしれませんが、気にする必要があります)。
- 左手と右手を交互に使うのが、キーボードを使用する最も速い方法です。
- マウスに触れないことは、できるだけ速くするための 2 番目の方法です。手を動かし、マウスをつかみ、移動し、キーボードに戻すのに時間がかかります (そして、手を正しい場所に戻したことを確認するためにキーボードを見る必要があることがよくあります)
Vim を使用すると生産性が大幅に低下する理由を示す 2 つの例を示します。
コピー/カット&ペースト。私はいつもこれをやっています。最近のエディタでは、Shift左手で押して、右手でカーソルを動かしてテキストを選択します。そしてCtrl+Cコピー、カーソルを動かしてCtrl+Vペーストします。
Vim の場合はひどいです:
yy
1 行をコピーします (行全体をコピーする必要はほとんどありません)。[number xx]yy
xx
行をバッファにコピーします。しかし、必要なものを選択したかどうかは正確にはわかりません。元に戻すために[number xx]dd
、これを実行しなければならないことがよくありますu
。
別の例は?検索と置換です。
- でPSPad: Ctrl+ をf押して検索したいものを入力し、 を押しますEnter。
- Vim の場合:
/
、検索したいものを入力し、各特殊文字\
の前に特殊文字がある場合は を押します。Enter
そして、Vim のすべてがそうなのですが、正しい処理方法がわからないようです。
私の質問は次のとおりです:
現代のエディターよりも生産性を高める Vim の使用方法は何ですか?
ベストアンサー1
Vimの問題は、 viを理解していないことです。
で切り取ることについて言及しyy
、行全体を切り取りたいことはほとんどないと不満を述べています。実際、ソース コードを編集するプログラマーは、行全体、行の範囲、コード ブロックを操作したいことがよくあります。ただし、 は、匿名コピー バッファー (またはviyy
で「レジスタ」と呼ばれる) にテキストをヤンクする多くの方法の 1 つにすぎません。
viの「禅」は、言語を話していることです。 はy
動詞ですyy
。y_
は、y
非常に一般的な操作であるため、入力しやすいように 2 重になっています。
これは、dd
P
(現在の行を削除し、コピーを元の場所に貼り付ける。副作用として匿名レジスタにコピーを残す) と表現することもできます。 およびy
「d
動詞」は、あらゆる動きを「主語」とします。つまり、 はyW
「ここ (カーソル) から現在の/次の (大きな) 単語の末尾までヤンクする」、 は「ここから ' ay'a
'というマークを含む行までヤンクする」です。
基本的な上下左右のカーソル移動しか理解できない場合、vi は「メモ帳」のコピーよりも生産性が高くありません。(構文の強調表示や、わずか 45KB 程度よりも大きいファイルを処理する機能はありますが、ここでは私の説明に従ってください)。
viには 26 個の「マーク」と 26 個の「レジスタ」があります。 コマンドを使用して、カーソルの任意の位置にマークを設定しますm
。各マークは、1 つの小文字で指定します。したがって、現在の位置にma
' amz
' マークを設定し、 ' z ' マークを設定します。'
(一重引用符) コマンドを使用して、マークを含む行に移動できます。 したがって、は ' a'a
' マークを含む行の先頭に移動します。 (バッククォート) コマンドを使用して、任意のマークの正確な位置に移動できます。 したがって、は ' z ' マークの正確な位置に直接移動します。`
`z
これらは「動き」なので、他の「発言」の主題としても使用できます。
したがって、任意のテキスト選択範囲を切り取る 1 つの方法は、マークをドロップすることです (私は通常、最初のマークとして' a '、次のマークとして' z '、別のマークとして ' b '、さらに別のマークとして ' e ' を使用します (15 年間viを使用してきましたが、対話的に 4 つ以上のマークを使用したことは一度もありません。対話的なコンテキストを妨げないマクロによるマークとレジスタの使用方法に関する独自の規則を作成します)。次に、目的のテキストのもう一方の端に移動します。どちらの端から始めてもかまいません。その後、単に を使用してd`a
切り取りまたはy`a
コピーします。したがって、このプロセス全体で 5 回のキーストロークのオーバーヘッドが発生します (「挿入」モードで開始し、Escコマンド モードから抜ける必要がある場合は 6 回)。切り取りまたはコピーを行った後、コピーを貼り付けるには 1 回のキーストロークが必要ですp
。
これはテキストを切り取ったりコピーしたりする 1 つの方法だと言いましたが、これは数ある方法の 1 つにすぎません。カーソルを移動したりマークを付けたりせずに、テキストの範囲をより簡潔に記述できる場合がよくあります。たとえば、テキストの段落にいる場合は、 と を使用して、それぞれ段落の先頭または末尾に移動できます{
。}
したがって、テキストの段落を移動するには、(3 つのキーストローク) を使用して切り取ります。(段落の最初または最後の行にいる場合は、それぞれまたは を{
d}
使用できます。d}
d{
「段落」という概念は、通常は直感的に適切なものにデフォルト設定されます。したがって、散文だけでなくコードにも有効です。
多くの場合、関心のあるテキストの一方の端またはもう一方の端をマークするパターン (正規表現) がわかっています。前方または後方の検索はviでの移動です。したがって、これらは「ステートメント」の「サブジェクト」としても使用できます。したがって、を使用して、d/foo
現在の行から文字列「foo」を含む次の行にカットしたり、y?bar
現在の行から文字列「bar」を含む最新の (前の) 行にコピーしたりできます。行全体が必要ない場合は、検索移動 (独自のステートメントとして) を使用し、マークを削除して、 `x
前述のコマンドを使用できます。
viには、「動詞」と「主語」に加えて、「オブジェクト」もあります (文法的な意味で)。これまでは、匿名レジスタの使用についてのみ説明しました。ただし、「オブジェクト」参照の前に(二重引用符修飾子)を付けることで、26 個の「名前付き」レジスタのいずれかを使用できます。つまり、 を使用すると、現在の行が ' a ' レジスタに切り取られ、 を使用すると、ここから "foo" を含む次の行までのテキストのコピーが ' b ' レジスタにヤンクされます。レジスタから貼り付けるには、貼り付けの前に同じ修飾子シーケンスを付けるだけです。 は、' a ' レジスタの内容のコピーをカーソルの後のテキストに貼り付け、 ' b ' から現在の行の前にコピーを貼り付けます。"
"add
"by/foo
"ap
"bP
この「接頭辞」という概念は、文法上の「形容詞」や「副詞」の類似物をテキスト操作「言語」に追加します。ほとんどのコマンド (動詞) と動作 (コンテキストに応じて動詞またはオブジェクト) は、数値接頭辞も使用できます。つまり、 は3J
「次の 3 行を結合する」という意味で、 はd5}
「現在の行からここから 5 番目の段落の終わりまでを削除する」という意味です。
これはすべて中級レベルのviです。どれもVimに固有のものではなく、学ぶ準備ができていればviにははるかに高度なトリックがあります。これらの中級の概念だけを習得すれば、マクロを記述する必要はほとんどないことに気付くでしょう。テキスト操作言語は十分に簡潔で表現力に富んでいるため、エディターの「ネイティブ」言語を使用してほとんどの操作を簡単に実行できるからです。
より高度なトリックの例:
多数の:
コマンドがありますが、最も注目すべきは:% s/foo/bar/g
グローバル置換テクニックです。(これは高度なものではありませんが、他のコマンドは高度なものになる可能性があります)。コマンド セット:
全体は、歴史的にviの以前のバージョンであるed (行エディター) および後にex (拡張行エディター) ユーティリティによって継承されました。実際、vi はexへのビジュアル インターフェイスであるため、このように名付けられています。:
:
コマンドは通常、テキスト行に対して実行されます。edとex は、端末画面が一般的ではなく、多くの端末が「テレタイプ」(TTY) デバイスであった時代に作成されました。そのため、非常に簡潔なインターフェイスを介してコマンドを使用して、テキストの印刷コピーから作業するのが一般的でした (一般的な接続速度は 110 ボー、つまり約 1 秒あたり 11 文字で、これは高速タイピストよりも遅く、複数ユーザーの対話型セッションでは遅延がよく発生しました。さらに、紙を節約する動機がしばしばありました)。
したがって、ほとんどのコマンドの構文には、:
アドレスまたはアドレスの範囲 (行番号) とそれに続くコマンドが含まれます。当然、リテラル行番号を使用して、:127,215 s/foo/bar
127 から 215 までの各行で最初に出現する "foo" を "bar" に変更することもできます。また、現在の行と最後の行にそれぞれ.
またはなどの省略形を使用することもできます。また、相対プレフィックスと を使用して、それぞれ現在の行の後または前のオフセットを参照することもできます。つまり、は「現在の行から最後の行まで、すべてを 1 行に結合する」ことを意味します。は(すべての行)と同義です。$
+
-
:.,$j
:%
:1,$
およびコマンド:... g
は:... v
、非常に強力なので、説明が必要です。:... g
は、パターン (正規表現) に一致するすべての行に後続のコマンドを「グローバルに」適用するためのプレフィックスです。 while は、:... v
指定されたパターン (「conVerse」の「v」) に一致しないすべての行にそのようなコマンドを適用します。 他のexコマンドと同様に、これらにはアドレス指定/範囲参照をプレフィックスとして付けることができます。 つまり、:.,+21g/foo/d
は「現在の行から次の 21 行まで、文字列「foo」を含むすべての行を削除する」という意味で、 は:.,$v/bar/d
「ここからファイルの最後まで、文字列「bar」を含まないすべての行を削除する」という意味です。
興味深いことに、一般的な Unix コマンドgrep は、実はこのexコマンドからヒントを得たものです (そして、そのドキュメント化の方法にちなんで名付けられました)。exコマンド(grep) は、「正規表現」(re) を含む:g/re/p
行を「グローバルに」「印刷」する方法をドキュメント化したものです。edとexが使用されていたとき、このコマンドは誰もが最初に学ぶコマンドの 1 つであり、ファイルを編集するときに最初に使用されるコマンドであることも少なくありませんでした。このコマンドは、現在の内容を印刷する方法でした (通常は、またはそのようなものを使用して、一度に 1 ページだけ印刷します)。:p
:.,+25p
:% g/.../d
または (その reVerse/conVerse 対応) が:% v/.../d
最も一般的な使用パターンであることに注意してください。ただし、ex
覚えておく価値のある他のコマンドがいくつかあります。
を使用しm
て行を移動したり、j
を使用して行を結合したりできます。たとえば、リストがあり、一致する (または逆に、あるパターンと一致しない) ものをすべて削除せずに分離したい場合は、次のように使用できます。... すると:% g/foo/m$
、すべての "foo" 行がファイルの末尾に移動されます。(ファイルの末尾をスクラッチ スペースとして使用するという別のヒントに注意してください)。これにより、すべての "foo" 行の相対的な順序が保持され、リストの残りの部分から抽出されます。(これは、次のような操作を行うのと同じです。1G!GGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d
(ファイルをその末尾にコピーし、末尾を でフィルターしgrep
、先頭からすべてのものを削除します)。
行を結合するには、通常、前の行に結合する必要のあるすべての行のパターンを見つけることができます (たとえば、箇条書きリストで「^ *」ではなく「^」で始まるすべての行)。その場合は、次を使用します: :% g/^ /-1j
(一致するすべての行について、1 行上に移動して結合します)。(ちなみに、箇条書きリストの場合、箇条書き行を検索して次の行に結合することは、いくつかの理由で機能しません... 1 つの箇条書き行を別の箇条書き行に結合することはできますが、どの箇条書き行もそのすべての継続に結合することはできません。一致する行に対してのみペアで機能します)。
言うまでもなく、古くからあるs
(substitute) を (global/converse-global) コマンドと一緒にg
使用できますv
。通常、そうする必要はありません。ただし、他のパターンに一致する行に対してのみ置換を実行したい場合を考えてみましょう。多くの場合、キャプチャ付きの複雑なパターンを使用し、バック参照を使用して、変更したくない行の部分を保持できます。ただし、一致と置換を分離する方が簡単な場合がよくあります。-- :% g/foo/s/bar/zzz/g
「foo」を含むすべての行で、すべての「bar」を「zzz」に置き換えます。(次のようなものは、:% s/\(.*foo.*\)bar\(.*\)/\1zzz\2/g
同じ行で「foo」が先行する「bar」のインスタンスに対してのみ機能します。これはすでに十分に不格好であり、「bar」が「foo」に先行するすべてのケースをキャッチするにはさらに変更する必要があります)
p
重要なのは、コマンド セットには、、s
およびd
行だけではないということですex
。
アドレス:
はマークを参照することもできます。したがって、 ' a ' マークと ' b:'a,'bg/foo/j
' マークの間の行にある文字列 foo を含む行を後続の行に結合するには、次のようにします。(はい、前述のコマンド例はすべて、このようなアドレス指定式をプレフィックスとして付けることによって、ファイルの行のサブセットに限定できます)。ex
それはかなりわかりにくいです (私は過去 15 年間でそのようなものを使用したのは数回だけです)。ただし、正しい呪文を考える時間を取ればおそらくもっと効率的に実行できたであろうことを、反復的かつ対話的に実行することがよくあることを率直に認めます。
もう一つの非常に便利なviまたはexコマンドは、:r
別のファイルの内容を読み込むことです。つまり、次のようにする:r foo
と、"foo" という名前のファイルの内容を現在の行に挿入します。
さらに強力なのは:r!
コマンドです。これはコマンドの結果を読み取ります。これは、viセッションを一時停止し、コマンドを実行し、その出力を一時ファイルにリダイレクトし、viセッションを再開し、一時ファイルからコンテンツを読み取るのと同じです。
さらに強力なのは、!
(bang) および:... !
( ex bang) コマンドです。これらのコマンドも外部コマンドを実行し、その結果を現在のテキストに読み込みます。ただし、これらのコマンドは、コマンドを通じてテキストの選択範囲をフィルター処理します。これを使用して、ファイル内のすべての行をソートできます。1G!Gsort
(はvi のG
「goto」コマンドです。デフォルトではファイルの最終行に移動しますが、先頭行の 1 などの行番号を前に付けることができます。これは、exバリアントに相当します。ライターは、テキストの選択範囲を再フォーマットまたは「ワードラップ」するために、Unix のfmtまたはfoldユーティリティとともに使用することがよくあります。非常に一般的なマクロは、(現在の段落を再フォーマットする) です。プログラマーは、インデントまたはその他のコード再フォーマットツールを使用して、コード全体またはその一部を実行するために、これを使用する場合があります。:1,$!sort
!
{!}fmt
:r!
およびコマンドを使用すると!
、外部のユーティリティやフィルターをエディターの拡張機能として扱うことができます。私は、データベースからデータを取得するスクリプト、Web サイトからデータを取得するwgetコマンドやlynxコマンド、リモート システムからデータを取得するsshコマンドなどで、これらを使用することがあります。
もう一つの便利なexコマンドは:so
( の短縮形:source
) です。これは、ファイルの内容を一連のコマンドとして読み取ります。通常、vi:source
を起動すると、暗黙的にファイルに対してを実行します~/.exinitrc
(当然のことながら、Vim は通常 に対してこれを実行します~/.vimrc
)。これを使用すると、マクロ、省略形、およびエディター設定の新しいセットをソースするだけで、エディター プロファイルをオンザフライで変更できます。こっそりと使えば、これを、必要に応じてファイルに適用するex編集コマンドのシーケンスを保存するトリックとして使用することもできます。
たとえば、私は 7 行のファイル (36 文字) を持っています。これは、ファイルをwcで実行し、その単語数データを含むファイルの先頭に C スタイルのコメントを挿入します。次のようなコマンドを使用して、その「マクロ」をファイルに適用できます。vim +'so mymacro.ex' ./mytarget
( viおよびVim+
のコマンド ライン オプションは通常、特定の行番号で編集セッションを開始するために使用されます。ただし、ここで行ったように、"source" コマンドなどの有効なexコマンド/式を に続けることができることはあまり知られていません。簡単な例として、一連のサーバーのイメージを再作成しているときに、SSH の既知のホスト ファイルから非対話的にエントリを削除するために、次を呼び出すスクリプトがあります。)+
vi +'/foo/d|wq!' ~/.ssh/known_hosts
通常、Perl、AWK、 sed (実際、grepのような、 edコマンドにヒントを得たユーティリティ)を使用してこのような「マクロ」を記述する方がはるかに簡単です。
コマンド@
はおそらく最も知られていないviコマンドです。10 年近く高度なシステム管理コースを時々教えていますが、これを使用したことがある人にはほとんど会ったことがありません。は、レジスタの内容をviまたはex@
コマンドのように実行します。例:システム上のファイルを検索し、その名前をドキュメントに読み込むために、私はよく を使用します。そこから不要なヒットを削除し、目的のファイルへのフル パスのみを残します。パスの各コンポーネントを面倒な - 操作で調べる代わりに(または、 viのコピーでタブ補完がサポートされていないマシンでたまたま立ち往生している場合はさらに悪いことになります)、私は単に を使用します。:r!locate ...
Tab
0i:r
(現在の行を有効な:rコマンドに変換するため)、"cdd
(「c」レジスタの行を削除する)@c
そのコマンドを実行します。
たった 10 回のキーストロークです (この式は"cdd
@c
私にとって実質的に指のマクロなので、一般的な 6 文字の単語とほぼ同じ速さで入力できます)。
冷静に考える
私はviのパワーの表面を少しだけ触れただけで、ここで説明したことはvimの名前の由来となった「改善」の一部でさえありません。ここで説明したことはすべて、 20 年または 30 年前のviの古いコピーでも動作するはずです。
私よりもずっと多くのviの力を活用した人々がいます。