EmacsのDiredモードは、shellコマンドが実行できるので重宝しています。

複数のファイルを一度に処理できて、置換文字も使えるので、shellと使い分けがナイスなのです。

で、この置換文字、shellのワイルドカード展開と似たような記法なので、なんとなく雰囲気で使っていましたが、これではいかん!ということで、まじめに調べてみました。

diredモードでのShellコマンドを実行する

まずは基本の話です。

Emacsのdiredモードには、ファイルに対してshellコマンドを実行するための関数が用意されています。

  • dired-do-shell-command (ショートカットは!)
  • dired-do-async-shell-command (&) # 非同期で実行

例えば、次のようなDiredバッファがあるとします。

 -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image1.jpg
 -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image2.jpg
 -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image3.jpg

画像ファイルの情報が知りたいので、ImageMagickのidentifyを使いたいとき、任意の行へカーソルを移動し、!を押せば、次のようなプロンプトが表示されます。

! on image1.jpg: 

ここで次のコマンドを入力して実行。

! on image1.jpg: identify

コマンドの末尾にファイル名が追加されて、次のように実行されるはず。

identify image1.jpg

実行結果は、エコーエリアにこんな感じで表示されるはず。

image1.jpg JPEG 1600x1200 1600x1200+0+0 8-bit sRGB 196921B 0.000u 0:00.000

これが基本的な使い方です。さらに複雑なコマンドを組み立てるのに、便利な置換文字について説明します。

置換文字*はShellコマンドが一回だけ実行

置換文字 * はファイル名へ展開されるので、複数のファイルを指定できるコマンドで使います。

例えば、2つのファイルをマークしているとき(mキーでマークできますね)

 * -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image1.jpg
   -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image2.jpg
 * -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image3.jpg

次のコマンドを入力すると(マークのあるものだけ対象なのでカーソル行はどの行でも同じ)。

tar cvf work.tar *

実際はこんなshellコマンドが実行されます。

tar cvf work.tar image1.jpg image3.jpg

置換文字?はファイル単位でコマンド実行

置換文字 ? はファイル単位で実行したいコマンドで使います。つまり * が一度しか実行されないのに対して、 ? はファイルの数だけコマンドが実行されます。

` ? ? がありますが、 ? `は前後にスペースが必要な場所で使います。

次のように、2つのjpgファイルを選択した状態で、

* -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image1.jpg
  -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image2.jpg
* -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image3.jpg

例えば、pngへ変換するなら、こんなコマンドを入力します。

convert ? -resize 150x150 s-`?`

次のconvertコマンドが2回実行されます。

convert image1.jpg -resize 150x150 s-image1.jpg
convert image3.jpg -resize 150x150 s-image3.jpg

前述したとおり、 ? には前後にスペースが必要なため、二番目の引数には、`?`を使いました。

このように、 ? はファイル単位でしか処理できないshellコマンドを使う場合に使います。

ちなみに、コマンドの実行順は、Diredバッファの表示順にしたがいます。つまり日付順へ変更すれば、shellコマンドはファイルの日付順で実行されます。

置換文字*""はワイルドカード

次は、ちょっと不思議な*""です。アスタリスクに続けて、ダブルクォーテーションふたつ入力します。

*""を使うと、shellコマンドへは*として渡されるので、いわゆるワイルドカード展開が使えます。

前述と同じく画像ファイルの一覧があるとき、

 -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image1.jpg
 -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image2.jpg
 -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image3.jpg

次のようなコマンドを実行した場合。

identify *""

ワイルドカード展開をするかプロンプトが表示されるのでYesを選択すれば、コマンドが実行されます。Noなら実行はキャンセルされます。

実行されるコマンドは、Shellでワイルドカードを使うのと同じです。

identify *

Diredバッファで選択されたファイルやカーソルの位置とは関係なく、Shellのワイルドカードを展開した結果になります。

置換文字を指定しない場合は、ファイル単位で実行

最初に書いたとおり、置換文字を使わない場合は、コマンドの末尾にファイル名が補完されます。

このとき、複数のファイルを選択していると、ファイル毎にコマンドが実行されます。

* -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image1.jpg
  -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image2.jpg
* -rw-r--r--  1 foobar  staff  196921  2 22 22:25 image3.jpg

ここでidentifyを実行すれば、コマンドが二回実行されます。

indentify image1.jpg
indentify image3.jpg	

次のように、まとめて一度だけの実行になるわけではありません。

indentify image1.jpg image3.jpg

さいごに

Diredモードのshellコマンドで使える置換文字についてみてきました。

このようなDiredでのshellの実行を覚えておくと、次のようなメリットがあります。

  • ファイルの一括処理に、Diredのファイル選択が利用できる
  • ファイル名を入力する手間が省ける
  • 実行結果をそのままEmacsで編集できる

以上、参考にしていただければ幸いです。

更新履歴

  • 2019-05-13 コマンドの例を変更。誤記の訂正。