よんちゅBlog

― このブログは自分用のメモや日々の問題などを共有するためのものです ―

20121005185841 お知らせ:  2013/07/17 ブログデザインをリニューアルしました。

Macのtmuxでクリップボードを使用、あとtmuxの自動起動とか

Mac上でtmuxを使用する場合、そのままではクリップボードとの連携ができません。
当然pbcopyやpbpasteなんかも使用できません。

この問題の解決方法に関しては以下のサイトが参考になります。

以上を踏まえた上でMacのtmuxでクリップボード機能を有効にする手順を説明していきます。
上記サイトとの差分が結構あるので最初から説明していきます。

Macのtmuxでpbcopy/pbpasteを有効にする

まずMacでクリップボード機能を有効にするために reattach-to-user-namespace (tmux-MacOSX-pasteboard ) というスクリプトをインストールします。
これは上記参考サイトにもある方法ですが、現在ではhomebrewからもインストールすることができるので、homebrewユーザはそちらを利用すると良いでしょう。

$ brew install reattach-to-user-namespace

そしてMacでtmuxを起動したときのみ reattach-to-user-namespace が有効になるようにtmuxのラッパースクリプトを用意します。
以下にあるスクリプトを使用すると良いのですが、これだとtmuxのセッションが既に存在している場合に強制的にアタッチしてしまうためtmuxの複数起動が行えません。

というわけで改良したスクリプトを用意します。
下記のスクリプトを tmuxx というファイル名でPATHの通った場所に置き、実行権限を与えます。

#!/bin/bash

# attach to an existing tmux session, or create one if none exist
# also set up access to the system clipboard from within tmux when possible
#
# e.g.
# https://gist.github.com/1462391
# https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard

if ! type tmux >/dev/null 2>&1; then
    echo 'Error: tmux command not found' 2>&1
    exit 1
fi

if [ -n "$TMUX" ]; then
    echo "Error: tmux session has been already attached" 2>&1
    exit 1
fi

if tmux has-session >/dev/null 2>&1 && tmux list-sessions | grep -qE '.*]$'; then
    # detached session exists
    tmux attach && echo "tmux attached session "
else
    if [[ ( $OSTYPE == darwin* ) && ( -x $(which reattach-to-user-namespace 2>/dev/null) ) ]]; then
        # on OS X force tmux's default command to spawn a shell in the user's namespace
        tmux_config=$(cat $HOME/.tmux.conf <(echo 'set-option -g default-command "reattach-to-user-namespace -l $SHELL"'))
        tmux -f <(echo "$tmux_config") new-session && echo "tmux created new session supported OS X"
    else
        tmux new-session && echo "tmux created new session"
    fi
fi

今後tmuxを起動する場合は以下のコマンドで起動するようにします。

$ tmuxx

これでpbcopy/pbpaste対応のtmuxが使用できるようになります。

tmuxxが大まかにどういう動きをするか(ここは読み飛ばしてOK)

  • tmux未インストール時はエラー
  • tmuxを既に起動している場合もエラー
  • Macの場合のみ reattach-to-user-namespace を有効にする
  • reattach-to-user-namespace 未インストール時でも無視して起動(だたしMacではクリップボード機能は使用できない)
  • tmuxをまだ起動していない場合は新規セッションを生成
  • ただし、デタッチ済みセッションが存在する場合は新規セッションを生成しないでデタッチ済みセッションにアタッチ(アタッチ済みセッションにはアタッチしない)

バッファからクリップボードへのコピーの機能にキーを割り当てる

次はtmuxのコピーモードでコピーした内容をクリップボードへ送る方法について解説します。

tmuxにはコピーモードという機能が存在します。
tmux上でターミナルのログをコピーする場合は通常このモードを使用します。
viのキーバインドemacsキーバインドが使えたり、検索ができたりとかなり便利です。

コピーモードのキーバインディングはviとemacsを選べます。
デフォルトはemacsですが、以下の設定でviにも切り替えられます。
~/.tmux.conf というtmuxの設定ファイルに以下のように記述します。

set-window-option -g mode-keys vi

以降コピーモードはviのキーバインドを元に説明します。

まず tmuxのプレフィックスキー + Ctrl-[ でコピーモードへ入ります。
(tmuxのデフォルトのプレフィックスキーは Ctrl-b です)
その後コピーしたい箇所へカーソルを移動(viキーバイドを使用)します。
spaceキー を押して範囲選択モードになり、でカーソルを移動して範囲を決めます。
Enterキー を押すと選択範囲をコピーすることができます。
また、コピーした内容をペーストする場合は、tmuxのプレフィックスキー + Ctrl-] で行います。

これでコピ&ペーストが行えるわけですが、コピーモードでコピーした内容は直接クリップボードへは送られず、tmux専用のバッファに蓄えられるのみとなります。
よってtmux外にペーストしたい場合は、そこからクリップボードに送ってあげる必要があります。

ここでまたもやスクリプトを用意することになります。
スクリプトの内容に関しては記事トップに記載した参考サイトにあるスクリプトを使用するか、以前私が書いた記事のスクリプトを使用します。

一応私が使用しているスクリプトを抜粋
下記スクリプトを tmux-pbcopy というファイル名でPATHの通った場所に置き、実行権限を与えます。

#!/bin/bash
if ! type pbcopy >/dev/null 2>&1 || ! type reattach-to-user-namespace >/dev/null 2>&1; then
    tmux display-message "Error: cannot copy to clipboard."
    exit 0
fi

COPY=$(tmux save-buffer -)
echo "$COPY" | reattach-to-user-namespace pbcopy

# メッセージ表示
LINES=$(echo "$COPY" | wc -l | tr -d ' ')
tmux display-message "Copy: $LINES lines"

修正(2012/10/17):
sh の echo コマンドではデフォルトで "-e" オプションが付いているようで、コピーする文字の中に "¥" が含まれているとエスケープシーケンスと解釈されてしまい、正常にコピーが行えませんでした。

よって、shebangを以下のように修正しました。

#!/bin/sh

#!/bin/bash

さらにtmuxのキーバインディングを設定します。

bind ^y run-shell 'tmux-pbcopy'

私の場合は Ctrl-y に割り当てていますが、そこはお好みで変更して下さい。

これで、tmuxのコピーモードでコピーした後に、tmuxのプレフィックスキー + Ctrl-y でクリップボードに送ること出来るようになります。

以上でクリップボード関連の設定は終了です。
最初は結構面倒ですが一度設定してしまえば便利ですので試しにやってみてはどうでしょう。

ログイン時にtmuxを自動起動

tmuxはサーバにログインして使用する場合に特に威力を発揮するわけですが、ローカルで使用していても結構便利です。
複数ウィンドウや複数ペイン(画面分割)、格好いいステータスライン、マウス無しで使えるコピーモードなどなど

しかし、慣れるには結構時間が掛かるもの。(自分もまだまだtmux初心者)
そんなときローカルでもtmuxを強制的に起動してtmuxを使わざるを得ない状況にしてみるのはどうでしょう。

というわけでシェルの設定ファイル(.bashrcや.zshrc)に以下の設定を追加

if [ -z "$TMUX" -a -z "$STY" ]; then
    if type tmuxx >/dev/null 2>&1; then
        tmuxx
    elif type tmux >/dev/null 2>&1; then
        if tmux has-session && tmux list-sessions | /usr/bin/grep -qE '.*]$'; then
            tmux attach && echo "tmux attached session "
        else
            tmux new-session && echo "tmux created new session"
        fi
    elif type screen >/dev/null 2>&1; then
        screen -rx || screen -D -RR
    fi
fi

これでターミナルを再起動すればtmuxが自動的に起動するようになります。
screenとの共存を意識してscreen起動時はtmuxが起動しないようにしています。
また、tmuxが存在しない場合でもscreenがあればそっちを起動するようにもしているので、tmuxはいいけどscreenはちょっと…という場合は適宜コメントアウトするなりして欲しい。

また、場合によっては自動ログインが邪魔になることもあるのでそんなときは無理せず無効にしましょう。