eshell (Emacs のシェルモード)

Emacs には eshell というコンソールのモードがあります。
これを使えば、 Un*x 系の開発では Emacs 上で編集、コンパイル、デバッグ、実行と全部できるので、ログインして Emacs を起動した後は全部 Emacs 上で作業するということもできます。

起動

eshell の起動は特にショートカットキーは割り当てられていないので、 M-x eshell で起動します。
ショートカットキーを割り当てる場合、例えば F8 キーに割り当てるには .emacs.el に次のように記述します。
(global-set-key [f8] 'eshell)
一度、 eshell を起動した後、再度 eshell のコマンドを実行すると起動済みの eshell のバッファが表示されます。
複数の eshell を起動したい場合には C-u をつけて C-u M-x eshell (C-u [F8]) のように実行します。

使用法

基本的に他のシェルと同じように使用できます。
補完、コマンド履歴操作のキーは次のようになります。
機能 キー
補完 [TAB]
途中まで書いたものにマッチする前の履歴 M-p, <up>
途中まで書いたものにマッチする次の履歴 M-n, <down>
前の履歴 <C-up>
次の履歴 <C-down>
補完はよくある TAB ですが、履歴は他のコンソールのシェルと違って C-p, C-n はバッファの行移動になり、 Alt(Esc) と組み合わせた p, n および矢印キーの上下が履歴となります。
ただし、 eshell は途中まで書いたものにマッチしたもの中から探します。
 $ ls ~/t [↑]   # コマンド履歴のうち、先頭が "ls ~/t" で始まる
                                 # ひとつ前の履歴を表示する 
他のシェルのような単純な履歴操作をしたい場合には、 Ctrl キーと組み合わせた矢印キーで行います。

パス区切り

ディレクトリの区切り文字は Windows 環境でも \ ではなく / を使用します。
Windows 環境では \ を使用することもできますが、 \ はエスケープ文字になっているので、 使用する場合には \\ と書く必要があります。

Emacs 関数の実行

eshell ではプログラムだけでなく、 Emacs lisp の関数も実行できます。

例えば、 grep, mandiff などは eshell 上で通常のコマンドのように実行すると、直接実行するのではなく、 lisp の関数を呼び出して M-x grep を実行したような動作になります。

前記の grep などは eshell モードでの関数として書かれている関数が呼び出されているのですが、 通常の lisp 関数も実行できます。
$ find-file foo.h  # ファイルのオープン
$ setq visible-bell t  # 値の設定
$ setq visible-bell    # 値の設定 (nil を設定)
$ compile "gcc main.c" # コンパイルの実行

エイリアス

他のシェルと同様にコマンドに別名をつけるエイリアスという機能があります。
登録する場合には ~/.eshell/alias に別名と実行するコマンドを記述します。
alias q exit
alias dir ls -l $*
alias msbuild-release MSBuild /p:Configuration=Release $*
alias ldd dumpbin.exe /DEPENDENTS $*
ここでの $* はエイリアスの後のコマンド引数になります。 通常のシェルでのエイリアスと違い、引数を $* で指定していないと 引数を受け取ってくれません。

リモートコンピュータ

Emacs にはもともと ange-ftp というモジュールで、 ftp を使ってリモートのファイルを 通常ファイルのように編集することができます。
そのときの書式は以下のようになります。
/ユーザー@サーバー名:パス
/サーバー名:パス
パスの部分にはサーバーでの絶対パスかユーザーのホームディレクトリからの相対パスを記述します。
パスワードは最初に接続する際に聞かれます。ユーザーを省略すると ~/.netrc に記述されたユーザーが使用され、パスワードも記述されていると聞かれずにそれが使用されます。

eshell ではこの ange-ftp を使って、リモートのディレクトリやファイルをローカルにあるものであるかのように 扱うことができます。例えば foo サーバーから bar サーバーへのファイルのコピーなどを FTP アプリを使わずに 行うことができます。
$ cp  /yohshiy@foo.com:/var/some/error.log  /yohshiy@bar.com:work/
ただし、リモートのディレクトリではフィルターの * が使えなかったり、 ファイル数が多いと ls に失敗したりと若干の制約はあります。


入門GNU Emacs (UNIX text processing)入門GNU Emacs (UNIX text processing)
(1999/09)
デボラ キャメロン、エリック レイモンド 他

商品詳細を見る
やさしいEmacs‐Lisp講座やさしいEmacs‐Lisp講座
(2011/06)
広瀬 雄二

商品詳細を見る
スポンサーサイト
 

eshell (Emacs のシェルモード) その2

Emacs の eshell の説明の続きです。
  • http://yohshiy.blog.fc2.com/blog-entry-41.html
今回は eshell のカスタマイズとコマンドを自作する方法の紹介です。

終了時の履歴確認

eshell を開いたままで emacs を終了しようとするととデフォルトでは、 毎回履歴を保存するかどうか聞かれて面倒です。
これを変更するには Customize の機能を使用します。
M-x customize-group などで eshell-hist のカスタマイズページを開き、 Eshell Ask To Save History の値を設定します。

emacs_eshell_hist.png

Ask がデフォルトの尋ねてくるタイプで、Never, Always save がそれぞれ聞かずに、履歴を保存しないタイプとするタイプです。

また、カスタマイズを使わずに .emacs.el で設定する場合には以下の行を追加します。
(setq eshell-ask-to-save-history 'always) 

コマンドの作成(簡易版)

eshell のコマンドを自分で作ることもできます。
これでショートカットキーで実行していた関数などを eshel 上のコマンドとして実行することができます。 簡単な方法は alias を使用することです。
C-h k などでキーに設定されている lisp の関数名を調べ、 ~/.eshell/alias に記述します。
例えば以下のように記述すると "exit-emacs" で Emacs を終了し、 "1" で他のウィンドウを閉じるようになります。
alias exit-emacs save-buffers-kill-emacs
alias 1 delete-other-windows
ただし、この alias を使った方法では、前回のコマンドのエイリアスと違い、引数をとるコマンドは指定できません。
("$*" を使って引数を指定できるようにしていても、エラーとなります。)

コマンドの作成

前項の方法では find-file などの引数をとる関数には使えません。 また、 grep などはそのまま通常のコマンドのようにかけるのに、 コンパイルはコマンドを "" で囲まないといけないので、面倒です。
こういった場合には emacs-lisp でコマンドを作成する必要があります。
こったものを作ろうとすると lisp の知識が結構必要になりますが、 例にあげたのような簡単なものであれば、 .emacs.el に設定を書く程度の知識で作成できるのではないかと思います。

作成コマンド記述ファイル

eshell のコマンドは el ファイルに記述し、 eshell ロード時にホックで呼び出すようにします。
例えば、 ~/elisp/ex-eshell.el に記述する場合は以下のコードを .emacs.el に記述します。
(setq load-path (append (list
                         "~/elisp"
                         )
                        load-path))
(add-hook 'eshell-load-hook '(lambda ()
                               (load "ex-eshell")
                               ))

引数固定のコマンド

eshell 用のコマンドの lisp 関数の名前は eshell/xxxx の形式にします。
実際にコマンド名として使用されるのは xxxx の部分です。

引数を固定した場合は簡単です。 関数の引数を呼び出したい関数に渡します。
次のコードはファイルを比較する ediff-files の関数を eshell コマンドにしたものです。
(defun eshell/ediff (fileA fileB)
  "差分を表示する"
  (ediff-files fileA fileB))

省略可能な引数を持つコマンド

引数を省略可能にするには &optional を関数の引数定義の前に記述します。
引数が省略された場合には引数に nil が入るので if 文を使って、処理を分けます。
  (if 判定条件
      (真の場合の処理)
    (偽の場合の処理))
以下の関数は find-file を使ってファイルをオープンし、 引数が省略されていた場合は直前に表示していたバッファを表示するコマンドです。
(defun eshell/open (&optional file)
  "ファイルのオープン。引数を省略した場合は直前のバッファを開く。"
  (if file
      ;; 引数あり
      (find-file file)
    ;; 引数なし
    (switch-to-buffer nil)
    ))

引数を結合して実行するコマンド

渡された引数をスペースで結合して関数を実行するコマンドの作成方法です。 これを使うと compile のような "" で囲んで引数を渡さなければいけない関数をコマンド化できます。

lisp の関数定義で可変引数を使う場合には &rest を使用します。
これを使うと渡された引数の残りがリストとして引数に格納されます。

以下は compile をコマンド化した例です。
(defun ex-eshell-join-args (args)
  (let (cmd)
    (while args
      (if cmd
          (setq cmd (concat cmd " " (car args)))
        (setq cmd (car args)))
      (setq args (cdr args)))
    cmd))

(defun eshell/c (&rest args)
  "指定したコマンドでコンパイルを実行する。
引数を省略した場合は前のコマンドで実行する"
  (if args
      ;; 引数あり
      (compile (ex-eshell-join-args args))
    ;; 引数なし
    (compile compile-command)
    ))
これで c のコマンドで、コンパイルが実行されます。 また、引数を省略すると直前に実行したコンパイルを再度実行します。
$ c   # 一番最初は compile-command のデフォルト値 (make -k など) が実行される
$ c gcc -o foo.exe main.c bar.c
$ c  # 前のコマンド (gcc -o foo.exe main.c bar.c) が実行される)

やさしいEmacs‐Lisp講座やさしいEmacs‐Lisp講座
(2011/06)
広瀬 雄二

商品詳細を見る
 

Emacs の eshell でバッファー末尾(EOB)から一文字戻る問題の対応

Emacs の 24.4 か 24.5 わかりませんが、 バッファーの末尾(EOB, End Of Buffer)で何かコマンドを実行するとカーソルが 1 文字戻る という不具合が入りこんでいました。 ほとんどの場合は大した問題ではないのですが、 eshell だとかなり不便です。
あまりちゃんとしたものではありませんが、対処方法を考えたので、 今回はそれを紹介します。

まず、何が問題かというと コマンドを書いていない場所から一文字カーソルを戻った場所は eshell では書きこみ禁止なところです。
eshell ではバッファーの最後にカーソルがあるのが普通の状態です。 ここからバッファーの切り替え(switch-to-buffer)やウィンドウの移動(other-window) を行ってから戻ると、一文字移動し直さないと入力できないことになり、かなり面倒です。

この現象は多分バグなので、そのうち修正されるとは思いますが、ちょっと調べた感じだと特に解決方法は見つかりませんでした。 そのため場当たり的ではありますが、対処方法を考えてみました。



どうやるかというと advice という機能を利用します。
バッファーの切り替え等のコマンドを実行した後、 eshell モードで EOB の一文字後ろの場合には EOB に移動するようにします。

以下がそのためのコード なので、 ~/.emacs.d/init.el 等に書いてみてください。
(defun ex-move-to-eob-if-eshell (&rest args)
  (when (eq major-mode 'eshell-mode)
    (let ((pos (point)))
      (goto-char (+ pos 1))
      (unless (eobp)
        (goto-char pos)))))

(advice-add 'switch-to-buffer :after 'ex-move-to-eob-if-eshell)
(advice-add 'other-window :after 'ex-move-to-eob-if-eshell)
(advice-add 'eshell :after 'ex-move-to-eob-if-eshell)
変更するコマンドは 3 つしか書いてませんが、 advice-add を追加すれば、他のコマンドでも移動するようになります。


 
このページをシェア
アクセスカウンター
アクセスランキング
[ジャンルランキング]
コンピュータ
36位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
4位
アクセスランキングを見る>>
カレンダー(アーカイブ)
プルダウン 降順 昇順 年別

02月 | 2017年03月 | 03月
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31 -


はてな新着記事
はてな人気記事
ブロとも申請フォーム
プロフィール

yohshiy

Author:yohshiy
職業プログラマー。
仕事は主に C++ ですが、軽い言語マニアなので、色々使っています。

はてブ:yohshiy のブックマーク
Twitter:@yohshiy

サイト紹介
プログラミング好きのブログです。プログラミング関連の話題や公開ソフトの開発記などを雑多に書いてます。ただ、たまに英語やネット系の話になることも。