2014年8月7日木曜日

tmux 環境作成自動化ツール tmux-agent 作ってみました

さっそくですが、タイトルのツール tmux-agent: tmux initial action agent を Github で公開してみました。一言で言いますと、所定の書法で記載したファイルを読み込むことで、ウィンドウやペインの作成・コマンド実行・レイアウト変更・同期モードオンなどのアクションを自動実行して tmux を開始してくれるツールです。bash で書いてます。一応 Mac OS X と CentOS 上で動作確認済み。

ちなみに、ほぼツールが出来上がった後に tmuxinator: Manage complex tmux sessions easily なる素晴らしいツールがあることに気づき ( ∑(゚Д゚) ← その時の心境)、 自作のツールをなかったコトにしようかと思いましたが、落ち着いてから見比べるといくつか tmux-agent の方が便利な部分もあったのでやっぱり公開しました。詳しくは tmuxinator との違い にまとめてみましたので、既に tmuxinator をご存じの方は参考までに。

以下、このツールを作った背景とか実際の利用例とかになります。

※ 追記 (2018/05/29) ※ tmux-agent に機能追加しました。詳しくは tmux-agent にプロンプト待ちと進捗メッセージ出力の機能追加 を御覧ください

目次

はじめに

改めましてですが、tmux 便利ですよね。昔は screen 使ってましたが、複数ペインの同時操作機能とかに惹かれて乗り換えて後、数年ほど愛用してます。

ただ、使い慣れてくるほどちょっとした不便さが気になってきまして、例えば

  • 複数ペインでそれぞれ別サーバに ssh ログインして同期モードにする
  • 作業に応じてウィンドウごとに別ディレクトリに移動する
  • (だいたいやることが決まってるような) コマンドの実行
  • ペインのレイアウト変更
  • セッション、ウィンドウのネーミング

とかってことを都度やるのが面倒になってきちゃいまして…。

要するに tmux 立ち上げた後の

  • ウィンドウやペインの作成とネーミング
  • コマンド実行
  • レイアウト変更
  • 同期モードオン

あたり自動化できないものかなー、と思いまして。

そんな時に tmuxで複数サーバの同時オペレーション | NaviPlus Engineers' Blog というブログを目にしまして、これは良いなと。tmux はコマンドベースで上記の操作が行えるので、スクリプト書けば自動化できちゃうわけですよね。

でわでわと用途に応じてスクリプト作ろうかなと思いましたが、スクリプト毎度書くのもやっぱり面倒なと。私の場合、あちこちのサーバにログインすることが多く、ログインの対象に応じて、ペインを複数作って同期モードオンにしたい場合や、個別にウィンドウを立てたい場合があったり、レイアウトを tiled にしたい場合がたまにあったりと、やりたいことの組み合わせもいろいろとありまして、それらのパターンに応じて毎度スクリプト作るのも辛いなぁと思いまして。せめてスクリプトじゃなくてシンプルな書法のファイルを読み込んで、動作を制御できるものがほしいと思ってました。

それで作ってみましたよというのが tmux-agent: tmux initial action agent になります。

インストール

単なる bash スクリプトなので、基本的にはダウンロードして適当なディレクトリに置けば OK なのですが、詳しくは Installation: tmux-agent を参照下さい。

使い方

例えば以下のような ~/.tmux-agent/web-log-sync-ssh-panes を用意しておき、

session: web-log-sync-ssh-panes
  window:
    pane-command: ssh ${pane}
    pane-command: tail -f /var/log/httpd/access_log
    pane-sync:
    pane: ${argv}

こんな感じで実行しますと

$ tmux-agent web-log-sync-ssh-panes web{1,3,5}
  • "web-log-sync-ssh-panes" という名称でセッション開始
  • web1, web3, web5 というホストに対して ssh ログインを実施
  • ログイン実施後に tail -f /var/log/httpd/access_log を実行 (ただし、ssh-agent などによりパスワード入力不要でログインできる状況である必要あり)
  • synchronize-panes モードを on にし、複数ペインに同時入力可能な状態に変更

といったことまでを自動でやってくれます。

イメージは以下のような感じ。

ちなみに、上のファイルを見て「この順番何?」と首をかしげた方もいるかと思いますが、tmux-agent で読み込むファイル内では、実行コマンドを記載する pane-command や、同期モードをオンにする pane-sync などは、対象となるペイン (pane で指定) よりも上に記載 するルールになってます。自分でもファイルのパッと見は奇妙だなぁと思うものの、実装で楽するためにこうしてます (この書式だと、各行の読み込み時に逐次で処理が進められる)。ウィンドウを指定する window なども同様です。書法の詳細については File Format - Keys: tmux-agent に記載がありますので詳しくはそちらで。

ペインだけでなく、複数ウィンドウのスタートも可能です。一つのコマンドを複数のウィンドウで実行することも可能ですし、ウィンドウごとに実行コマンドを変えることも可能です。ここらへんはペインに対しても同様なことができます。

session: host-status${id}
  window-command: df
  window: disk
  window-command: free
  window: memory
  window-command: top
  window: cpu
  window-command: tail -f /var/log/${window}
  window: messages secure maillog

筋は良くないのかもしれませんが、ファイルを読む以外にも、既存セッションが存在する場合はそのアタッチをしたりもします。要するに tmux で作業始める際は全部この tmux-agent から始められるようにしたかったという。

$ tmux-agent <ファイル or 既存セッション名>

同名のファイルとセッションが存在してた場合はファイル優先になります。セッションの読み込みを優先したい場合もあるかと思いますので、そこらへんの使い分け方については後述の 使用例: セッション名の自動採番 を参照下さい。

Bash/Zsh の補完関数利用

Bash, Zsh を利用してる方向けに、補完関数も作ってみました。

それぞれ、source コマンドなどで読み込んでもらうことで、tmux-agent コマンドの後でタブを入力することでファイル名が補完されます。Zsh の場合は既存セッションについても補完されます。

[bash]

$ tmux-agent <TAB>

app-ssh-windows     no-title          tail-webservs-log
multi-ssh-windows   sync-ssh-panes    web-log-sync-ssh-panes

[zsh]

$ tmux-agent <TAB>

multi-ssh-windows   -- init-action
multi-ssh-windows0  -- attached
multi-ssh-windows1  -- detached
no-title            -- init-action
no-title0           -- detached
sync-ssh-panes      -- init-action
tail-webservs-log   -- init-action
tail-webservs-log   -- attached

この補完機能でだいぶ使い勝手は良くなるかなと思ってます。

使用例いろいろ

以下では、自分なりにユースケースに応じて作った機能について、紹介します。

セッション名の自動採番

とりあえず何かしらの作業始める時にと以下のようなファイルを用意しておくとします。

# file: no-title
session: no-title

1度目は以下のようにファイルを読み込み、セッション no-title を起動します。

$ tmux-agent no-title

そんな折、別の作業が入ったとします。セッションをデタッチして、再度同じコマンドでセッションを起動しようとすると、tmux-agent の機能上、既存のセッションをアタッチしてしまいます。

こういったケースで、常に新しいセッションを始めるようにしたい場合には ${id} 変数を使ってみて下さい。

# file: no-title
session: no-title${id}

こうすると、

$ tmux-agent no-title

を実行するごとに、no-title0, no-title1, no-title2 といった、${id} に新しい番号が採番された新しいセッションが作成されます。つまり、新しい作業を始める場合は常に上記のコマンドでよく、既存のセッションをアタッチしたい場合は

$ tmux-agent no-title2

などとすれば良いわけですね。

これは用途ごとに要否が異なる機能だと思いますので、使い分けていただければ幸いです。

ちなみに、以下のように session の中身が空の場合はデフォルト値として ${file}${id} が入りますので、その手の用途の場合は空にしておく方が楽かもしれません。(${file} はファイル名に自動変換されます)

# file: no-title
session:

レイアウト設定

以下のような指定で、ペインのレイアウト指定も行えます。

# file: topdirs-sync-panes-tiled
session: 
  window: 
    pane-command: cd ${pane}
    pane-command: ls
    pane-layout: tiled
    pane: /usr /var /tmp /bin

2014/08/07 時点での 最新版である tmux 1.9a では以下のレイアウトが指定可能です。

  • even-horizontal
  • even-vertical
  • main-horizontal
  • main-vertical
  • tiled

個人的には作業に応じて、even-vertical, even-horizontal, tiled を使い分けてますね。

カスタムレイアウト設定

tmuxのwindow, pane設定を一発で再現できるtmuxinatorが便利 で紹介されていて「こんな方法があるのか!」と初めて知ったのですが、ビルトインのレイアウトの他にも、自作したレイアウトを再現することも可能です。

もともと tmux にある機能で、まず以下のコマンドで既存セッションのレイアウト一覧が取得可能です。

$ tmux list-window -a -F "#S: #W: #{window_layout}"

session: window: 77cf,80x24,0,0{54x24,0,0[54x16,0,0,828,54x7,0,17,830],25x24,55,0,829}

この 77cf,80x24,0,0{54x24,0,0[54x16,0,0,828,54x7,0,17,830],25x24,55,0,829} の部分がレイアウトになっており、select-layout にこの文字列を与えることでレイアウトが再現されます (レイアウト取得時とペイン数が同じ事が前提です)。

tmux-agent でもファイルの pane-layout: にレイアウトをセットしておくことで、カスタムレイアウトを再現可能です。

# file: custom-layout
session:
  pane-layout: 77cf,80x24,0,0{54x24,0,0[54x16,0,0,828,54x7,0,17,830],25x24,55,0,829}
  pane: {0..2}

ちなみに、もう少し複雑なレイアウトのサンプルを tmux-agent: init-action-files.sample/custom-layout-sample に用意してます。

tmuxinator との違い

tmuxinator は非常に良さ気なので基本そちらを使ってもらえればイイと思うのですが、いくつか tmux-agent 特有の機能もありますのでまとめました。(2014/08/07 時点)

tmux-agent 特有の機能

  • Bash のブレース展開が利用可能 (window: や pane: の指定において)
      • server-{a,b,c} → server-a server-b server-c
      • log.080{4..8} → log.0804 log.0805 log.0806 log.0807 log.0808
  • 同じようなコマンドを複数のウィンドウやペインで実行する場合、以下のようにシンプルに記載可能。以下の例では、対象サーバ 6 つに対してそれぞれウィンドウを開き、その中でそれぞれログごとに 3 つのペインを開いてコマンドを実行する。

    # file: remote-servers-log-display
    session:
      window: app{8,9} web{3..6}
        pane-command: ssh ${window}
        pane-command: tail -f /var/log/${pane}
        pane: messages secure cron
    
  • tmux-agent のコマンドライン引数に与えた文字列を ${argv} 変数を介してコマンドに組み込んで実行可能。上記のいくつかの例で示すように、ログイン先ホスト名などをコマンドライン引数で動的に変更できる。
  • ${id} 変数の利用により、一つのファイルから複数のセッションを開始することが可能。

tmux-agent 微妙だなぁと思う部分

  • tmux-agent のファイルは File Format: tmux-agent に記載する通りのオレオレな適当なものであるのに対し、tmuxinator はまっとうな Yaml のフォーマットであるため、ウィンドウ・ペイン・コマンド等の関係が綺麗に表現されています。そのため後者の方が読み書きも容易かと。tmux-agent のファイルは bash でお手軽に実装するのを優先したため、このような少々妙なフォーマットになってます。
  • pre, pre_window (全体の前処理、各ウィンドウを開く際の前処理) などの気の利いた設定が tmux-agent にはありません。(他にも socket_name, tmux_options, tmux_command など)
  • tmuxinator は tmuxinator open [project] で直接ファイルをエディタから編集する機能を備えてます。tmux-agent はそういった気の利いたものはありません ^^; (直接 vi なり emacs なりで編集お願いします)

終わりに

その他詳細は README: tmux-agent にて拙い英語にて紹介してます。

Sample Files も用意してますので、自作のファイルを作る場合はそれを元に作っていただくのが良いかと。編集の際には File Format をご覧ください。

tmux をある程度使い込んでる方には、tmuxinator なり拙作 tmux-agent なりは使って損はないツールかなという気がしてます。みなさんのターミナル生活がより快適なものになれば幸いです。

それでわ

参考資料

2014年5月16日金曜日

RSpec を Homebrew で簡単に Mac OS X にセットアップできた話

突然ですが Homebrew 便利ですよね。ガッチリとした開発環境としてどうなのかはあまりその用途で使ってないのでどうこう言えませんが、最新のソフトウェアがかなりお手軽にセットアップ・管理できるのは助かってます。先日も「あぁ、Ruby 最新が 2.1.2 かぁ。触ってみたいけどインストールがなぁ… (´・ω・`)」などと考えていましたが、

$ brew upgrade ruby

であっという間に終わりました。

欲を出して、RSpec もちょっと使ってみたいなぁと思って調べてたのですが、やはり gem 管理が基本のようで、「まあいいけども…」と思ってたら brew の brew-gem なるパッケージ経由でこちらも簡単にセットアップできてしまいました。以下のような感じです。

$ brew install brew-gem
$ brew gem rspec

これでインストール自体はおしまいです。rspec 関連のファイルは /usr/local/Cellar/rspec/ 以下にインストールされてます。

ただ、一点問題がありまして実行ファイルへのパス ($PATH)、Ruby ライブラリとしてのパス ($RUBYLIB) ともに未設定です (将来的には誰かが自動設定されるように何とかしてくれそうですが)。

とりあえずパスを設定すれば使えるんですが、rspec のバージョンが上がっても書き換えなくていいような設定の仕方にしてます。~/.bashrc (~/.zshrc も可) に書いておけば自動的に設定してくれるはず。

RSPEC_PATH=$(find /usr/local/Cellar/rspec -name "exe" | tr '\012' ":" | sed 's/:$//g')
RSPEC_RUBYLIB=$(find /usr/local/Cellar/rspec -name "lib" | tr '\012' ":" | sed 's/:$//g')

export PATH=$PATH:$RSPEC_PATH
export RUBYLIB=$RUBYLIB:$RSPEC_RUBYLIB

これだけやれば、以下のように rspec が使えちゃいます。

$ rspec -v
2.14.8

$ rspec --init
  create   spec/spec_helper.rb
  create   .rspec

ちなみに、brew-gem でインストールしたパッケージはあくまで gem 経由でインストールしただけで基本 brew の直轄管理なので、削除する時は以下で OK です。

$ brew uninstall rspec

以上、拍子抜けに簡単でつい記事にしてしまいました。

ちなみにこの記事を書いた時の諸々のバージョンは以下の通り。

  • OS: 10.9.2 (Mavericks)
  • Xcode: 5.1.1
  • brew: 0.9.5
  • ruby: 2.1.2
  • rspec: 2.14.8

さて今度は RSpec について調べねば…。

2014年2月16日日曜日

FlashAir 上の写真を一括ダウンロードして日付ディレクトリにアーカイブするシェルスクリプト作りました

昨年はいろいろあって後半はブログを更新できずじまいでしたが、最近自分と家族用に作ったシェルスクリプトを GitHub に公開 しましたのでそのご紹介をば。

どういったものかというと、下図のように FlashAir 上の写真を手元の Macintosh に一括ダウンロード (ただし既にダウンロード済のものはスキップ) し、それらを撮影日ごとに日付ディレクトリにアーカイブする、というシロモノです。撮影日情報は ExifTool で画像や動画ファイルの Exif ヘッダから取得してます。(無線アクセスポイントの切替を自動化したかった関係から、Macintosh 以外の OS では動作しません。すいません。)

追記: (2014/03/31) 先月やっと Mavericks にアップデートしたら、キーチェーン内の無線アクセスポイントのパスワードの属性情報の構成が変わってて上手く動作しなかったのでそちら修正しました。 v1.1 Release であれば Mavericks 対応しています。また、ターゲットとなるパスワードが保存されているキーチェーンの場所も「ログイン」から「ローカル項目」なる場所に変わっており、後者を CLI で参照するインターフェースはまだ提供されてません。そこはキーチェーンの管理ユーティリティで元の「ログイン」側にキーチェーンをコピーしてもらってから使う、というアドホックな対応になってます。

目次

セットアップや使い方など

利用に関しての必要最低限は GitHub:mo-ya/flashair-photos-sync で紹介してますので、そちらを参照ください。

こちらのブログではこれを作った背景や、作る時に勉強になった事などを書きたいと思います。

FlashAir についての感想

カメラとかその周辺デバイスとか全然詳しくなくて、FlahsAir も家族が買ってきたものです。そこでやっと FlashAir なるものがあることを知ったぐらいです。

その後ウェブで少し調べたんですが、ASCII.jp さんの記事 (だいぶ以前のものですが) が FlashAir について他製品 (Eye-fi とか) と比較しながら紹介してて勉強になりました。

いまさらながら、面白いアイディアだなと思いました。この手の機器って自分の頭の中で勝手にクライアント機器だろという思い込みがあったんですが、確かに写真を保存してるストレージ自身で無線アクセスポイント立てちゃえば出先でもどこでもスタンドアロンで動作できるんですよね。設定も他のアクセスポイント機器との関係を考えなくて済むのでシンプルで済みますし。

このスクリプトを作った理由

さて、じゃあなんでわざわざこんなもの作ったかといいますと、な話です。

FlashAir の紹介ページ を見ると以下の用途を想定しているようです。

  • 撮った写真をスマホやタブレットなど高解像度・大画面ですぐ見れる
  • 出先で撮った写真をその場でスマホなどでシェア
  • ↑ これらをするのにキャリア回線や Wifi アクセスポイント不要 (FlashAir 自身がアクセスポイントになるから)

これらの使い方はそれはそれで便利ですし良いんですが、うちの場合はこういった事もやりたいと思いまして。

  • カメラで撮った写真・動画は全部手元(PC やファイルサーバ)に保存
  • 撮影日情報を元に日付フォルダ分け
  • 保存した写真・動画は SD カードから消して OK

理由としては

  • わざわざ「どの写真を残すか」とか手動でフォルダ分けとかやってる時間がない
  • 保存用と考えると SD カードはサイズが小さいので、空き容量が無くなってきたら「どれ消そうか…」とか悩まずにばさっと消してしまいたい

といったことになるのかなと。そんなわけで以下の処理を自動化したツールを作ったというわけです。

  • FlashAir からの写真の一括ダウンロード (重複ダウンロードは行わずに)
    • FlashAir からのデータ転送速度は必ずしも早くないので、全写真のダウンロードを毎回やってると時間がかかりすぎます。なので、過去ダウンロードした写真はダウンロードしないようになってます。
  • 画像・動画ファイルの Exif ヘッダに記録されている撮影日でフォルダ分けして保存
    • これも毎度手でやってると面倒でそのうち止めちゃう→フォルダ内がカオスに、ってなことになりそうなので自動化しました。
  • 無線アクセスポイントの切替(例: 自宅 Wifi→FlashAir→自宅 Wifi)
    • FlashAir から写真をダウンロードしようとすると、当然自宅の Wifi から FlashAir に切り替えて戻すってのが必要なんですが、何度か手動でやってみたんですが意外に面倒で…。そんなわけでこの切替も自動化しました。これで写真データのダウンロードから PC (ファイルサーバでも OK) への保存までスクリプト実行一発で OK になりました。

ちなみに保存先は手元の PC とファイルサーバの両方に同時に保存できるようにしてあります。私の場合、前者は閲覧用、後者はバックアップと家族でのシェア用にしてます。

このスクリプトを作って変わったこと

このスクリプトのお陰で、日頃の生活での写真・動画の保存は以下の 2 アクションで済むようになりました。

  1. スクリプト実行

    $ flashair-photos-sync.sh -f -y
    
  2. カメラの電源オン (FlashAir を動作させるため)

後は待ってれば前回ダウンロード後に新たに撮られた写真・動画が勝手にダウンロードされて日付ディレクトリに保存 (ついでに iPhoto にも登録) してくれます。

写真を閲覧する時は Finder やプレビューよりも iPhoto の方が便利なので、フォルダごと iPhoto にインポートしてます。写真が入ってる日付フォルダがそのまま iPhoto の「アルバム」扱いになるので、iPhoto のアルバム管理も一石二鳥でできちゃってます。ちなみにスクリプト実行後に自動で iPhoto 登録する方法は GitHub:mo-ya/flashair-photos-syncPOST_SCRIPT の説明を参照下さい。

理想的には、ダウンロードと保存まで全部バックグラウンドでやってくれるのが望ましいんですけどね。まあ無線アクセスポイントが勝手に切り替わるタイミングができても嫌ですし、FlashAir の無線アクセスポイント立ち上げのためにカメラの電源入れる必要もありますんで、自動化できるのはここまでかなと考えてます。

勉強になったこと

Mac OS X の無線アクセスポイント切り替えについて

始めは CUI でどう無線アクセスポイント切り替えたら良いのか分からず、いろいろ調べました。

やっと見つけたのは networksetup(8) なるコマンドです。無線デバイスについての大抵の操作はできるようなんですが、このスクリプトで使ってるのは以下の 2 通りだけです。1 つ目が現在の Wifi ネットワークの SSID の表示、2 つ目が別の SSID への切り替えです。

$ networksetup -getairportnetwork <device>

$ networksetup -setairportnetwork <device>

これで切り替えはできるようになったんですが、どうも切り替えてすぐに写真ダウンロードしたり、ファイルサーバに接続しようとするとうまくいかず。

無線アクセスポイント切り替え後に IP アドレスなどのネットワークパラメータ割り当てを確認した後でもどうもうまくいかない場合があって何かと思ってたんですが、どうやらネットワークパラメータ割り当てた後に /etc/resolv.conf を更新してるようなんですね。

実際には /etc/resolv.conf/var/run/resolv.conf のシンボリックリンクになっており、後者が更新されます。このファイルはシステム環境設定の [ネットワーク] で指定した DNS サーバ等の情報が反映されるファイルなようで、DHCP にしている場合は DNS の情報が DHCP サーバから送られてきてから更新されるようです。

/etc/resolv.conf が読み込み可能になったことを確認してからの写真ダウンロード、ファイルサーバ接続はさっくりと上手くいくようになり、ここまで来てやっと無線アクセスポイント切り替えが自動化できました。

キーチェーンからのパスワード取得方法

もう一つ勉強になったのが、Mac OS X 標準のパスワード管理ユーティリティであるキーチェーンへの CUI でのアクセス方法についてです。

こちらも始めは「そもそもそんなことできるんだろか?」という感じでしたが、調べてみると security(1) なるコマンドでできることが。

無線アクセスポイントのパスワードにアクセスするのは以下のような感じです (これは Mountain Lion の場合。Mavericks は後述)。

$ security find-generic-password -g -s com.apple.network.wlan.ssid.<SSID>

具体的には以下のような出力です。実はパスワードは標準エラー出力に出ててちょっとはじめ戸惑いましたが、分かってしまえば簡単に扱えます。なお、パスワードを表示する前には下記の 2 つのウィンドウのどちらかが表示され、[許可] をクリックするか、管理者の名前とパスワードを入力する必要があります (この 2 つの違いは後述)。

$ security find-generic-password -g -s com.apple.network.wlan.ssid.flashair

許可すると以下のようにキーチェーンに登録されている各種情報とパスワードが表示されます。

keychain: "/Users/user/Library/Keychains/login.keychain"
class: "genp"
attributes:
    0x00000007 <blob>="flashair"
                 :
    "acct"<blob>="AirPort"
                 :
    "desc"<blob>="AirPort network password"
                 :
    "svce"<blob>="com.apple.network.wlan.ssid.flashair"
    "type"<uint32>=<NULL>
password: XXXXXXXX            ← これだけは標準エラー出力に出るので注意

dump-keychain オプションを使えば、パスワード以外の情報一式を抜き出せます。無線アクセスポイントのパスワードとして何を保存しているか一覧を見たいなら以下のように。

$ security dump-keychain | grep com.apple.network.wlan.ssid.

    "svce"<blob>="com.apple.network.wlan.ssid.flashair"
    "svce"<blob>="com.apple.network.wlan.ssid.homewifi"    
                      :

追記: なお、Mavericks だと無線アクセスポイントのパスワードを管理するキーチェーン内の属性情報の持ち方が変わっているため、以下のように問い合わせる必要があります。

$ security find-generic-password -g -s AirPort -a flashair

keychain: "/Users/user/Library/Keychains/login.keychain"
class: "genp"
attributes:
    0x00000007 <blob>="flashair"
                 :
    "acct"<blob>="flashair"
                 :
    "desc"<blob>="AirPort network password"
                 :
    "svce"<blob>="AirPort"
    "type"<uint32>=<NULL>

ちなみに、ファイルサーバへの接続パスワードはこのような感じで取り出せます。 (こちらは Mountain Lion、Mavericks ともに違いありません)

$ security find-internet-password -g -s <サーバ名> -r "<プロトコル> "

具体例はこちら。

$ security find-internet-password -g -s 192.168.1.10 -r "smb "

keychain: "/Users/user/Library/Keychains/login.keychain"
class: "inet"
attributes:
    0x00000007 <blob>="192.168.1.10"
    0x00000008 <blob>=<NULL>
    "acct"<blob>="user"
                :
    "ptcl"<uint32>="smb "
    "srvr"<blob>="192.168.1.10"
    "type"<uint32>=<NULL>

security(1) を見つける前は、独自でどっかにパスワード保存するしかないかなぁと思ってましたが、キーチェーンから取り出すという筋の良い形にできてラッキーでした。

ログインキーチェーンとシステムキーチェーンの違い

キーチェーン内のパスワードにアクセスする際、[許可] をクリックするか、管理者の名前とパスワードを入力するかしなければならないと書きましたが、どちらになるかは対象のパスワードが ログインキーチェーンシステムキーチェーン のどちらに保存されているかによります。

これはアプリケーションフォルダの下のユーティリティフォルダ内の [キーチェーンアクセス] ユーティリティを呼び出してみるとどちらに何が登録されているかひと目で分かります。

ログインキーチェーンはユーザレベルで管理できるものであるため、特にパスワード入力の必要なくアクセス許可できる上、[常に許可] といったことも可能です。一方でシステムキーチェーンはアクセスの際に管理者のユーザ名とパスワードの入力が求められ、[常に許可] といったこともできません。

ただ、システムキーチェーンに入っているパスワードをログインキーチェーンに移動するのは意外と簡単です。やり方は以下の通りです。

  1. アプリケーションフォルダの下のユーティリティフォルダ内の [キーチェーンアクセス] でキーチェーンの管理ユーティリティを呼び出す
  2. 左上ペインで [システム] を選択
  3. システムキーチェーンに管理されており、ログインキーチェーンに移動したいパスワードを選択して Ctrl-C
  4. 左上ペインで [ログイン] を選択し、Ctrl-V

とりあえずこれでログインキーチェーンにもパスワードが登録されたので、security(1) によるアクセス時にいちいちパスワードを入力する必要はなくなります。

ただ、キーチェーンはときおり壊れる (?) らしく、あまりあれこれいじらない方が良いようです。私の手元でも (普段使わないので困ってはいませんが) アクセスできない項目があったりします…。

追記: Mavericks だとキーチェーンの種別に ローカル項目 というものが増えています。想像ですが、おそらく iCloud キーチェーンに絡むものではないかなと。2014/03/31 現在、手元の security(1) コマンドではこのキーチェーンにはアクセスができていません。少しウェブ上も調べましたが、やはり CLI でこのローカル項目にアクセスする方法は提供されていないようです。そのうちローカル項目や iCloud キーチェーンに CLI でアクセスできるインターフェースが提供されると助かるのですが…。

キーチェーンへのアクセスの「常に許可」を辞めたいときには?

余談ですが、一度 security(1) によるアクセスを [常に許可] にして、その後やっぱり許可を止めたい場合には以下のようにします。

  1. [キーチェーンアクセス] ユーティリティを呼び出す
  2. 該当の項目をダブルクリックし詳細情報を表示
  3. [アクセス制御] をクリック
  4. [これらアプリケーションによるアクセスを常に許可] という場所にアプリケーションのリストが表示される。一度 security(1) に [常に許可] を出している場合は、以下のように security がリストに含まれているはず
  5. security を選択して、下の 「ー」をクリック
  6. 右下の [変更内容を保存] をクリック

これで、再度 security(1) で呼び出した場合は、また許可を促すウィンドウが出てくるようになります。

おわりに

さて、今回自宅用に作ったスクリプトをそれっぽい感じで公開したので、ちょっと「へー」と思ったことなどブログにまとめてみました。

使える環境が結構限られてるのでどーなのかなとは思いましたが、お役に立てば幸いです。いい加減 OS も Mavericks に上げなきゃと思ってるので、そちらも動作確認したら追記します。

追記: Mavericks にアップデートしたら、色々変わってて慌てて修正しました(汗)。ブログの更新はさらに 1 ヶ月かかってしまいましたが…。まだ私は iCloud キーチェーン使ってませんが、使いはじめるとまた手直ししなきゃいけないかもしれませんね ^^;

でわでわ