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