Software Design連載記事を掲載します。

株式会社技術評論社の許可を得て掲載しています。
草稿なので細かい部分は実際の記事とは異なることがあります。

他の記事は左下にある「■雑誌連載中(全文公開)」から見られます。

Emacsに備わった最強のファイラー

 ども、Emacs情報サイトrubikitch.comの運営が軌道に乗ってきたるびきちです。今回採り上げるのは、diredというEmacsに備わったファイラーです。ファイラーとは、ディレクトリ内のファイルを一覧したり、ファイルを開いたり、1つ以上のファイルをコピー、移動、削除などを行うアプリケーションです。これまで「文字入力の一元化」というコンセプトでEmacsのテキストエディタとしての機能を解説してきましたが、実はファイル管理においてもそれが活きてきます。

 ファイラーは今や星の数ほど存在します。有名どころにFDCloneやMidnight Commanderなどがありますが、筆者は使ったことがありません。カスタマイズ性を謳ったファイラーもありますが、diredはそんなのとは次元そのものが異なります。diredはEmacs Lispで書かれているので、diredの挙動「すべて」を自由にコントロールできるのです。そう、すべてです。なぜならdired含むEmacs LispアプリケーションはコアとなるLisp関数をも再定義可能です。もしそこにバグがあったり気に入らなければ自分で再定義して解決できます。その他のファイラーは「ここがこうだったらいいのに」と思ってもカスタマイズできない部分に遭遇したら解決できません。コアの再定義などできるはずがありません。

 すべてがコントロール可能という特性は、Emacs入門者にとっては特にメリットに感じないかもしれません。けれども、Emacsを長年使っていくことで自分の知識・スキルが上がるようになれば、自分にとっての理想像ができてきます。入門者でも使えるし、熟練者の要望にも応えてくれるのがEmacs Lispのすごいところです。diredの理想像を表現したものとして、diredの拡張パッケージがたくさん存在します。

 Emacsユーザにとって最強のファイラーはdiredです。EmacsがLispという言語を拡張言語として採用した時点で最強は決まっています。diredがあれば、他のファイラーはいりません。歴史があって安定していてたくさんの拡張パッケージがあって、その気になれば自分で自在にコントロールできるのですから。

起動方法

 diredの主な起動方法は2つあります。ひとつめはC-x C-fでディレクトリを開く方法です。C-x C-fは本来ファイルを開くコマンドですが、ディレクトリを開こうとするとdiredが立ち上がります。C-x C-fがファイルとディレクトリそれぞれにおいて別の挙動を持っていることから、diredはEmacsの生態系において自然に溶け込んでいることがわかります。

 もうひとつはC-x dを使う方法です。これはdiredコマンドであり、ワイルドカードが使えるメリットがあります。C-x C-fでワイルドカードを指定するとマッチするファイルすべてを開きますが、C-x dはマッチするファイルのみをdiredで表示します。たとえばC-x d *.txtで拡張子.txtのファイルがdiredで表示されます。

 シェルを使っていればとりあえずlsを実行してファイルを一覧したくなるときがありますよね。そんなときはdiredを起動すればファイルが一覧されるだけでなく、ファイルに対してコピーやシェルコマンド実行などの処理が行えます。複数のファイルをマークすることで、簡単に複数のファイルを処理できます。

20140811013609.png
Fig1: C-x d /tmp/*.txt を実行したところ

ファイルを開く

 diredを使えば、そこからファイルを開くことは簡単になります。ファイル名が一覧されているので、たとえファイル名がうろ覚えでも確実に目的のファイルを指定できます。その場合、diredを開いた直後にisearchを使うと早いです。

 diredからファイルを開くのはRETですが、eとfも使えます。aも似ていますが、ファイルを開いた後にdiredバッファを削除する点が異なります。

 diredを見ながらファイルを開くにはoです。oはdiredバッファの隣のウィンドウでファイルを開きます。ウィンドウが分割されていないときは分割します。

 diredからファイルを閲覧する方法は2つあります。C-oではdiredの隣にファイルを開きますがウィンドウは選択しません。vはRETと同様にdiredからそのファイルにカレントバッファを切り替えますが、その後にview-modeにします。view-modeとは、読み込み専用バッファで閲覧に特化した操作法を提供するマイナーモードです。ファイルを閲覧するときはview-modeにしておけば、Ctrlを使わずに操作できるので、指をいたわることになります。

コピー・移動・削除

 diredはファイラーなので、ファイルに対して様々な処理が行えます。ファイルのコピー、移動(リネーム)、削除などがあります。これらは一貫して大文字のキーに割り当てられています。

 Table1は主なファイル操作をまとめたものです。他にもchmodなり圧縮なりありますが、使用頻度が低いので覚える必要はありません。後述するシェルコマンド実行機能を使えば間に合うからです。

 ファイルを削除するDを実行すると、念のため本当に削除するかどうか聞いてきます。とくにLinuxのファイルシステムにおいてファイル削除は復元困難なので慎重に行う必要があります。削除してハッと気付いても遅いです。大惨事を防ぐためには毎日バックアップをとることが重要です。筆者はバックアップに『何度も』救われました。

 ファイルのリネームと移動は内部的には同じ意味です。同一ディレクトリ内においては文字通りリネームですが、別のディレクトリにおいては「移動」と表現を変えているに過ぎません。移動とはフルパスのリネームと考えてください。

Table1: 主なファイル操作

キー 操作
C コピー
D 削除
R リネーム・移動
H ハードリンク作成
S シンボリックリンク作成

マーク

 複数のファイルを選択して一括した処理を行うのもファイラーの重要な機能です。diredではこの機能を「マーク」といいます。

 マークのコマンドは最低限2つだけ覚えればよいです。ファイルをマークするm、マークを外す(アンマーク)するuです。余裕があればマークを反転させたり、すべてアンマークしたり、マークされたファイル間のカーソル移動、正規表現に基くマークも知っておくに越したことはありません。

 ファイルをマークした後に前述のファイル操作コマンドを使えば、操作対象がマークされたファイルになります。Fig2において、CategoryGamesとCategoryGuileEmacsをマークしているので、処理対象がこれらのファイルであることがわかります。ファイル操作コマンドはマークの有無で一貫した挙動をとります。

20140817012310.png
Fig2: 2つのファイルをマークしCを押したところ

Table2: 主なマークコマンド

キー 操作
m カーソル位置のファイルをマーク
u カーソル位置のファイルをアンマーク
t マークを反転
U 全ファイルをアンマーク
M-{ マークされたファイルへ移動(後方)
M-} マークされたファイルへ移動(前方)
% m 正規表現にマッチするファイルをマーク
* % 正規表現にマッチするファイルをマーク
% g 内容が正規表現にマッチするファイルをマーク

diredを2画面ファイラーとして使う

 diredを2画面ファイラーとして扱うことができます。List1の設定を加えてdiredを2つ開いて配置させたとき、一方のdiredがコピー、移動、リンク作成しようとしたとき、デフォルトの対象ディレクトリが他方のdiredのディレクトリになります。(Fig3)

== List1: 2画面ファイラー用の設定

(setq dired-dwim-target t)

==

20140817012747.png
Fig3: 隣のウィンドウのディレクトリがデフォルト!

ファイル削除に特化した方法

 ファイルを削除する方法は実はDだけではありません。ここで紹介する方法は削除に特化したやり方であり、不要なバックアップファイルなどの掃除もできます。

 diredにはマーク以外にも「削除フラグ」というマークの変種があります。マークは一般的なファイル操作に使えるのに対して、削除フラグは削除に特化したマークといった感じです。

 ファイルを削除する流れは削除対象のファイルに削除フラグをつけて、xで実際に削除をします。カーソル位置のファイルに削除フラグをつけるにはdを押します。d→xという流れです。もちろんマークを使ってm→Dでも削除できます。

 削除フラグを付けるコマンドは他にもあります。#はauto-saveファイルすべてが対象です。~はバックアップファイルが対象です。これらのファイルには#や~が付くので覚えやすいかと思います。

 % &はゴミファイルに削除フラグをつけます。dired-garbage-files-regexpという正規表現にマッチしたものをゴミファイルとみなします。デフォルト設定はList2です。% &を使いたい人は適宜修正してください。

== List2: dired-garbage-files-regexpのデフォルト設定

(setq dired-garbage-files-regexp
      (concat (regexp-opt
               '(".log" ".toc" ".dvi" ".bak" ".orig" ".rej" ".aux"))
              "\\'"))

==

 % dは正規表現にマッチするファイルに削除フラグを付けますが、実際にところはM-!でrmを実行した方が早いと思います。diredの機能をすべて使うのではなく、既存の知識と併用して柔軟に対処するのが大事です。

 マークと削除フラグは* cで交換できます。マークを削除フラグにするには * c * D を、削除フラグをマークにするには * c D * を使います。

Table3: 削除フラグ関係のコマンド

キー 操作
d カーソル位置のファイルに削除フラグ
x 削除フラグのファイルを削除
# auto-saveファイルすべてに削除フラグ
~ バックアップファイルすべてに削除フラグ
% & ゴミファイルすべてに削除フラグ
% d 正規表現にマッチするファイルに削除フラグ
* c * D マークを削除フラグに
* c D * 削除フラグをマークに

diredからシェルコマンドを実行する

 diredからシェルコマンドを実行するには「!」を使います。これさえ知っていれば、たとえ他のファイル操作コマンドを忘れていたとしても同じことができます。Emacsからシェルコマンドを実行するM-!との対比から、忘れにくいと思います。

 !も他のファイル操作コマンドの例に漏れず、マークの有無で挙動が変わります。マークがないときは現在のファイルを、マークがあるときはマークされたファイルが対象になります。

 !の基本的な挙動は、シェルコマンドの後ろにファイル名を指定したシェルコマンドを各々のファイルに対して実行するものです。たとえば、2つのファイルaとbにマークされている状態で「echo 1」を実行したら、「echo 1 a」と「echo 1 b」が実行されます。

 ファイル名の埋め込み方は任意に指定できます。デフォルトではシェルコマンドの後ろに1ファイルとなりますが、「?」「*」という文字を使えば別な場所にできます。たとえば、diredで/tmp/を開いていて、ファイルaとbにマークがしてあるとします。

Table4: !を実行した結果

指定したシェルコマンド echo x echo x ? echo * x echo ? x
実行されるシェルコマンド echo x a echo x a echo a b x echo a x
  echo x b echo x b   echo b x
実行結果 x a x a a b x a x
  x b x b   b x

 シェルコマンドの最後に「&」を指定すれば、非同期実行になります。つまり、シェルコマンドを実行中でもEmacsを操作できます。

diredでファイル名のみを表示する

 通常のdiredはls -lの出力結果を表示するため、ファイル名がどうしても右端に表示されてしまいます。これだと、単にファイル一覧のみを見たい場合には煩わしいものです。そこで、dired-details.elを使ってファイルの詳細を隠してしまいましょう。

 Emacsにはバッファの任意の部分を非表示にする機能があります。dired-details.elではこの機能を活用することで、実際のバッファにはデータ上はls -lの結果が入っていますが、見かけ上はファイル名のみを表示できるのです。

 dired-details.elと組み合わせると便利なのがdired-toggle.elです。M-x dired-toggleを実行するとdiredを左端に表示させ、qでdiredをウィンドウごと削除します。dired-details.elによりファイル名のみが表示される状態で使うと、カレントディレクトリのファイルが左端にきれいに表示されるようになります。(Fig4)

 どちらもMELPAというパッケージ登録所に登録されているので、パッケージの設定(List3)さえしてしまえばEmacsの中でインストールできます。

M-x package-refresh-contents
M-x package-install dired-details
M-x package-install dired-toggle

== List3:パッケージを使うための初期設定

(package-initialize)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)

==

== List4:dired-details/dired-toggleを使うための設定
(require 'dired)
(require 'dired-details)
(dired-details-install)
(setq dired-details-hidden-string "")
(setq dired-details-hide-link-targets nil)
==

20140911084423.png
Fig4: dired-details + dired-toggle

真のDirectory editor「wdired」

 最後にお伝えしたいのは、diredをDIRectory EDitorと呼ぶのにふさわしいwdiredという機能です。wdiredとはWritable DIREDの略で、diredバッファを書き換えてその結果をファイル名に反映させるというものです。ファイルのリネームや移動という作業を普段のEmacsコマンドで行えるのが何よりの強味です。wdiredでできることは以下のことです。

  • ファイルのリネーム
  • ファイルを別のディレクトリへ移動(同時にリネームも可)
  • パーミッションの変更
  • シンボリックリンク先の変更

 wdiredは標準機能ですがキーに割り当てられていないので、List5の設定をしておきます。

== List5: wdiredの初期設定

(require 'wdired)
(setq wdired-allow-to-change-permissions t)
(define-key dired-mode-map "e" 'wdired-change-to-wdired-mode)

==

 使い方は極めて簡単で、eでEditable Diredモードにした後、ファイル名を書き換え、C-x C-sでその結果を反映させるだけです。diredバッファを普通のファイルであるかのように書き換えて保存するだけなので極めて直観的です。

 wdiredの場面では置換と矩形編集が便利です。M-%で置換したり、C-x r tで一連のファイルに別のディレクトリ名を挿入したりしましょう。

 また、パーミッションのビットでSPCを押せばそのビットがトグルするので、wdiredでパーミッションも変更できます。

 書き換え結果を破棄するにはC-c C-kです。

終わりに

 今回はdiredを取り上げました。通常のファイル操作はもちろんのこと、シェルコマンドの連携とwdiredは超強力です。MELPAにはたくさんのdired拡張があるので、ぜひあなた好みのdiredを作り上げていってください。

 筆者のサイトrubikitch.comではEmacsの情報発信基地をめざすべく、定番情報や最新情報を日々更新しています。さらにステップアップしたい方はメルマガ登録お願いします。http://rubikitch.com/juku/ Happy Emacsing!

本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。