検証環境

この文章は主に以下の環境でテストした結果を記述しています。

  • Emacs
    • GNU Emacs22.3
    • GNU Emacs23.1
  • OS
    • Windows XP SP3
    • Mac OS X 10.6.2 以上
    • Mac OS X 10.5.8(Intel,PPC)
  • Shell
    • Bash 3.2.48
    • Zsh 4.3.10
  • Package Manager
    • Cygwin 1.7.1
    • Fink 0.29.10
    • MacPorts 1.8.2

Warning

未検証の環境によっては問題が発生する可能性があります。どんなことでも良いので問題点に気づいたらコメントいただけるとありがたいです。よろしくお願いします。

Emacs での Shell Mode に関する基礎知識

Emacs から Shell を利用する Mode は大きく分類すると 3種類あります。

  • shell
  • term (ansi-term)
  • eshell

それぞれに特徴があります。

shell


M-x shell 



Zsh  Bash 便

term (ansi-term)


M-x term  M-x ansi-term term  ansi-term 

Zsh  Bash 

eshell


M-x eshell 

Emacs Lisp  Shell shell  Emacs Lisp Emacs Lisp 

Windows  Cygwin  Bash  Zsh 便

 Emacs Lisp 

どのモードを利用するか

Bash や Zsh を利用したいので、この記事では term を利用してカスタマイズしていきます。

利用する Shell について


Bash  Zsh  Zsh  Zsh Bash 

Windows での Shell の準備

Windows の場合は Bash 、Zsh を利用するなら Cygwin 等でインストールする必要があります。

http://www.cygwin.com/

また fakecygpty をコンパイルしてパスの通った場所に置いておくと良いでしょう。

http://www.meadowy.org/meadow/browser/trunk/nt/fakecygpty.c

gcc -o fakecygpty.exe fakecygpty.c
cp fakecygpty.exe f_zsh.exe
cp fakecygpty.exe f_bash.exe
cp fakecygpty.exe f_ssh.exe

Mac OS X での Shell の準備

Mac OS X にデフォルトでインストールされている Zsh はマルチバイト文字が正常に扱えませんのでマルチバイト文字を利用する場合は fink もしくは MacPorts を利用してマルチバイト対応でコンパイルした Zsh を導入する必要があります。

この手順は必須ではありませんが日本語ファイル等を扱う方はインストールしておいた方が無難かと思います。

fink の場合は以下のようにします。Trees で unstable/main を有効にする必要があります。また最新情報に更新してからインストールした方が良いでしょう。

# 最新情報に更新します
sudo fink selfupdate
# zsh-multibyte をインストールします
sudo fink install zsh-multibyte

MacPorts の場合は以下のようにします。最新情報に更新してからインストールした方が良いでしょう。

# 最新情報に更新します
sudo port -v selfupdate
sudo port -v sync
# zsh-devel をインストールします
sudo port install zsh-devel +mp_completion +pcre

Bash に関しては特に問題はないはずです。

Emacs 側の設定

Emacs で Shell を正常に利用するためには Emacs と Shell の双方に設定が必要です。

Emacs の設定は $HOME/.emacs.d/init.el (旧 .emacs.el) で設定します。

PATH の設定

Mac OS X では Emacs をダブルクリックにて GUI として起動すると PATH を正常に引き継げないようですし、また環境依存性を減らすためにも init.el の中で PATH の設定をした方が無難です。

PATH と exec-path を同時に設定した方が普通の場合は使いやすいと思われますので、以下のようにして PATH を通します。

;; より下に記述した物が PATH の先頭に追加されます
(dolist (dir (list
              "/sbin"
              "/usr/sbin"
              "/bin"
              "/usr/bin"
              "/opt/local/bin"
              "/sw/bin"
              "/usr/local/bin"
              (expand-file-name "~/bin")
              (expand-file-name "~/.emacs.d/bin")
              ))
 ;; PATH と exec-path に同じ物を追加します
 (when (and (file-exists-p dir) (not (member dir exec-path)))
   (setenv "PATH" (concat dir ":" (getenv "PATH")))
   (setq exec-path (append (list dir) exec-path))))

MANPATH も設定しておくと良いでしょう。

(setenv "MANPATH" (concat "/usr/local/man:/usr/share/man:/Developer/usr/share/man:/sw/share/man" (getenv "MANPATH")))

利用する Shell の設定


 Shell ZshBashcmdproxy 

f_zsh  f_bash  fakecygpty.exe Meadow  NTEmacs  Bash  Zsh 

cmdproxy  NTEmacs  Emacs 


;; shell の存在を確認
(defun skt:shell ()
  (or (executable-find "zsh")
      (executable-find "bash")
      ;; (executable-find "f_zsh") ;; Emacs + Cygwin を利用する人は Zsh の代りにこれにしてください
      ;; (executable-find "f_bash") ;; Emacs + Cygwin を利用する人は Bash の代りにこれにしてください
      (executable-find "cmdproxy")
      (error "can't find 'shell' command in PATH!!")))

;; Shell 名の設定
(setq shell-file-name (skt:shell))
(setenv "SHELL" shell-file-name)
(setq explicit-shell-file-name shell-file-name)

文字コードの設定

筆者は文字コードを utf-8 に統一しています。 set-language-environmentprefer-coding-system を設定することでほぼ utf-8 になります。

(set-language-environment  'utf-8)
(prefer-coding-system 'utf-8)

term  locale-coding-system  file-name-coding-system 

Windows  sjis 

Mac OS X  utf-8  utf-8-hfs  utf-8-hfs  ucs-normalize  Emacs23.2 Emacs22  Emacs23.1  http://repo.or.cz/w/emacs.git/blob_plain/HEAD:/lisp/international/ucs-normalize.el 
(cond
 ((or (eq window-system 'mac) (eq window-system 'ns))
  ;; Mac OS X の HFS+ ファイルフォーマットではファイル名は NFD (の様な物)で扱うため以下の設定をする必要がある
  (require 'ucs-normalize)
  (setq file-name-coding-system 'utf-8-hfs)
  (setq locale-coding-system 'utf-8-hfs))
 (or (eq system-type 'cygwin) (eq system-type 'windows-nt)
  (setq file-name-coding-system 'utf-8)
  (setq locale-coding-system 'utf-8)
  ;; もしコマンドプロンプトを利用するなら sjis にする
  ;; (setq file-name-coding-system 'sjis)
  ;; (setq locale-coding-system 'sjis)
  ;; 古い Cygwin だと EUC-JP にする
  ;; (setq file-name-coding-system 'euc-jp)
  ;; (setq locale-coding-system 'euc-jp)
  )
 (t
  (setq file-name-coding-system 'utf-8)
  (setq locale-coding-system 'utf-8)))

locale-coding-systemecho $LC_ALL 等で文字コードを確認して Terminal の locale に合せる必要がありますので環境に合せてください。

システムの terminfo を利用しない設定


Zsh  term  4m 

 Emacs  Shell  TERM  TERM=eterm-color eterm-color  terminfo 

 eterm-color  init.el 
;; Emacs が保持する terminfo を利用する
(setq system-uses-terminfo nil)

もしこの設定をしても 4m のような文字が消えない場合は 環境変数 TERM の設定 を実施してください。

エスケープを綺麗に表示する

ls などで色が出るようにしていると Shell のエスケープ文字が表示されてしまう場合があります。これを避けるには以下の設定を init.el に記述します。

(autoload 'ansi-color-for-comint-mode-on "ansi-color" nil t)
(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)

term 呼び出しキーの割り当て


 M-x 便

 init.el  C-ct  Shell 
(global-set-key (kbd "C-c t") '(lambda ()
                                (interactive)
                                (term shell-file-name)))

Shell 側の設定

どうしても Emacs の Shell の中では動作しない設定も存在します。また Terminal では必要ですが Emacs の Shell の中では不要な設定も存在しています。

処理の分岐


Shell  Emacs  Shell  Terminal 

Emacs  term  EMACS term 
echo $EMACS

とりあえずは以下のように分岐可能です。

if [ "$EMACS" ];then
  # Emacs 内で起動した時の処理
else
  # Terminal から起動した時の処理
fi

Zsh では右プロンプト等が Emacs 内だと邪魔になりやすいようです。Bash や Zsh の設定は人により非常に複雑化しているので Emacs なのかを判定する以下のような関数を作成しておきます。

isemacs(){
   [[ "$EMACS" != "" ]] && return 0
   return 1
}

便

 Emacs  term 調

環境変数 TERM の設定


Mac OS X  Zsh MacPorts  terminfo  terminfo Shell  terminfo 

terminfo  Emacs  eterm-color  terminfo 
# eterm-color.ti から生成した terminfo を利用する。tiファイルのパスは自分で判断して変更してください
tic -o ~/.terminfo /usr/local/share/emacs/23.1/etc/e/eterm-color.ti
# Mac OS X で app 形式の場合は以下のような場所にあります
tic -o ~/.terminfo /Applications/Emacs.app/Contents/Resources/etc/e/eterm-color.ti

terminfo を生成しても動作しない場合は以下のような設定を Shell の設定ファイルに記述すると良いでしょう。

if [ "$EMACS" ];then
  export TERM=Eterm-color
fi

eterm-color を利用すると多少普段の Terminal とは挙動が異なります。もし普段の Terminal と表示の挙動を同じにしたい場合は、 以下のような設定にすると良いでしょう。

export TERM=xterm-color

TERM の値は利用している Terminal によって異なりますので、 echo $TERM して自分の環境を確認してください。

Emacs からの Shell 利用を標準以外の機能で拡張する

ここまでの設定は Emacs の標準機能ですが、標準の機能だけで快適さを追求しても個人的には満足な状態にはなりませんでした。

標準以外の機能を追加してより便利にしてみます。

multi-term.el


multi-term  term 

term 




Emacs 

exit 

Emacs  term  shell 




 multi-term.el 
cd ~/.emacs.d
curl -O http://www.emacswiki.org/emacs/download/multi-term.el

init.el には以下の設定をします。

(require 'multi-term)
(setq multi-term-program shell-file-name)

M-x multi-term 

使

"C-z""C-x""C-c""C-h""C-y""<ESC>"  Emacs 


(add-to-list 'term-unbind-key-list '"M-x")

term は char mode と line mode があり デフォルトは char mode です。

multi-term の char mode では C-n で次の行に移動、 C-p で前の行に移動といった Emacs 的な動作ができ、 M-nM-p でコマンドの履歴をたどることができます。

さらに Emacs的な操作にしたければ以下のように hook に設定を追加します。

(add-hook 'term-mode-hook
         '(lambda ()
            ;; C-h を term 内文字削除にする
            (define-key term-raw-map (kbd "C-h") 'term-send-backspace)
            ;; C-y を term 内ペーストにする
            (define-key term-raw-map (kbd "C-y") 'term-paste)
            ))

また multi-term 呼びだし用にキーも割り当てておくと良いでしょう。

(global-set-key (kbd "C-c t") '(lambda ()
                                (interactive)
                                (multi-term)))

キーで起動した時に複数起動でなく既存のバッファを選択したい場合は以下のように設定します。

(global-set-key (kbd "C-c t") '(lambda ()
                                (interactive)
                                (if (get-buffer "*terminal<1>*")
                                    (switch-to-buffer "*terminal<1>*")
                                (multi-term))))

multi-term  exit  term  multi-term  multi-term  Shell 

multi-term-next  multi-term-prev  Shell 


(global-set-key (kbd "C-c n") 'multi-term-next)
(global-set-key (kbd "C-c p") 'multi-term-prev)

 elscreen  Terminal  screen 

multi-term  Shell  Emacs 

shell-pop.el

shell-pop は shell のウィンドウを簡単に呼び出すための拡張です。

cd ~/.emacs.d
curl -O http://www.emacswiki.org/emacs/download/shell-pop.el

デフォルトでは multi-term には対応していませんが以下のように設定すると対応できます。以下の設定では F8 を押すと、 multi-term で起動した shell がフレームを分割して起動します。

(require 'shell-pop)
;; multi-term に対応
(add-to-list 'shell-pop-internal-mode-list '("multi-term" "*terminal<1>*" '(lambda () (multi-term))))
(shell-pop-set-internal-mode "multi-term")
;; 25% の高さに分割する
(shell-pop-set-window-height 25)
(shell-pop-set-internal-mode-shell shell-file-name)
;; ショートカットも好みで変更してください
(global-set-key [f8] 'shell-pop)

全部設定しても満足できない場合

term だけで全てを簡潔させることを考えず Emacs の機能を利用してみると良いかもしれません。

Emacs には以下のような機能がありますのでその利用を検討してみてください。

  • FTP や SSH 等の操作は tramp を利用する
  • grep は M-x grep を利用する
  • M-! で shell コマンドの実行ができる
  • Emacs Lisp からは (shell-command-to-string "pwd") のようにすると Shell コマンドの実行結果を文字として取得できる

現在の課題

この記事はまだ検証不足です。問題点に関しては Twitter 経由や下のコメントフォーム等からコメントをいただけると大変ありがたいです。

よろしくお願いします。



2011-01-23: Emacs Lisp (Thanks YMD)

2010-11-16: shell-pop-set-window-height (Thanks cyber-nanomomonga)

2010-04-04: ucs-normalize.el 

2010-03-28: MANPATH 

2010-03-27: 

2010-03-26: shell-pop (Thanks miurah3)

2010-03-24: terminfo (Thanks @nanasess)

2010-03-22: system-uses-terminfo t nil MacPorts  Zsh  Variants (Thanks @nanasess)

2010-03-21: 

関連エントリ

Author: sakito Updated: 2011年01月23日() category: /emacs Permalink: Permalink
このエントリーをはてなブックマークする はてなブックマーク数 このエントリーをdel.icio.usに登録する このエントリーを Tumblr する このエントリーに Twitter 経由でコメントする
以下はゲストコメント可能です。名前とメールアドレスは任意の物を入力していただいてかまいません。
blog comments powered by Disqus

このページの先頭へ

copyright (CC-by) 1999-2024 sakito
Powered by pyblosxom. Theme: TheBuckmaker.