DebianにおけるsSMTP導入方法とGmailを利用したメール送信方法のまとめ

sSMTPは、SMTPプロトコルのみに対応した、非常に軽量・シンプルなMTAである。
メール送信機能を利用したいが、Sendmail等の複雑なMTAは使用したくない時などに便利である。
この記事では、sSMTPの導入方法と、Gmailを利用したメールの送信方法を簡単にまとめる。

環境

  • Debian Wheezy 7.7 (x86_64, kernel:2.6.32-042stab092.2)
  • ssmtp (2.64-7)
  • heirloom-mailx (12.5-2)
  • Gmail (2014-12-15時点)
  • exim4 (4.80-7+deb7u1)

設定手順

設定は、以下の手順でおこなう。

  1. 既存のMTAの削除
  2. sSMTPのインストール
  3. 設定ファイルの記述
  4. 設定ファイルのファイル属性の変更
  5. ログインユーザのmailグループへの追加
既存のMTAの削除

(MTAがインストールされていない場合は、このセクションは実行しなくても良い。)


sSMTPは、他のMTAと同時に使用すると、競合することがある。そのため、既存のMTAがインストールされている場合は、該当するプログラムをsSMTP導入前に削除しておく。
今回使用した環境ではexim4がインストールされていたため、あらかじめ削除する。
具体的には、端末上で以下のコマンドを入力して、サービスの停止・exim4関連のパッケージの削除をおこなえば良い。


# service exim4 stop
# aptitude remove '~nexim4'

sSMTPのインストール

次に、sSMTPのインストールをおこなう。
Debian Wheezyでは、公式リポジトリにsSMTPのパッケージが用意されている。
ここでは導入を簡単にするため、このsSMTPパッケージを利用することにする。


端末上で以下のコマンドを入力し、sSMTPをインストールする。


# aptitude install ssmtp
上記のコマンドを実行後、"aptitude show ssmtp"や、"whereis ssmtp"等でsSMTPがインストールされていることを確認しておく。

設定ファイルの記述

sSMTPの設定ファイルは、/etc/ssmtp/ssmtp.confである。
このセクションでは、上記のファイルを編集・記述し、sSMTPが動作するように設定をおこなう。


sSMTPの動作に最低限必要な設定項目は、以下の6項目である。


Mailhub : "Mailhub=smtp.gmail.com:587"を指定
UseTLS : "UseTLS=Yes"を指定
UseSTARTTLS : "UseSTARTTLS=Yes"を指定
AuthUser : "AuthUser=hogehoge"、GmailのユーザIDを指定
AuthPass : "AuthPass=piyopiyo"、Gmailのパスワードを平文で指定
AuthMethod : "AuthMethod=LOGIN"を指定
上記6つの項目を、/etc/ssmtp/ssmtp.confに記述すれば良い。


----------※2015/03/16(Mon)追記分----------
MTAもしくはユーザ側でメールのヘッダFrom(注:エンベロープFromではない)を書換えたい場合は、

FromLineOverride=yes
を/etc/ssmtp/ssmtp.confに記述する。
----------以上2015/03/16(Mon)追記分----------



以下、設定後のssmtp.confと、標準で用意されているssmtp.confとの差分である。

# diff /etc/ssmtp/ssmtp.conf /etc/ssmtp/ssmtp.conf.original
10c10
< mailhub=smtp.gmail.com:587
---
> mailhub=mail
22,28d21
< 
< UseTLS=Yes
< UseSTARTTLS=Yes
< 
< AuthUser=your_gmail_id
< AuthPass=your_gmail_password
< AuthMethod=LOGIN

以上で、設定ファイルの記述は完了である。
(より詳細な設定をおこないたい場合は、man ssmtp.confを参考にすると良い。)

設定ファイルのファイル属性の変更

次に、sSMTPが設定ファイルにアクセスできるようにするため、/etc/ssmtp/ssmtp.confの所有グループを"mail"に変更する。
端末上で、以下のコマンドを入力して、所有グループの変更をおこなう。


# chown root:mail /etc/ssmtp/ssmtp.conf

また、設定ファイル内には、ユーザIDとパスワードを平文で記述している。そのため、パーミッションを変更して、設定ファイルにアクセスできるユーザを限定しておく。


# chmod 640 /etc/ssmtp/ssmtp.conf

ログインユーザのmailグループへの追加

sSMTPを通じてメールを送信する場合、MUAを使用するユーザが"mail"グループに所属している必要がある。
ここではログインユーザのmailグループへの追加をおこなう。


具体的には、端末上で以下のコマンドを入力する。


# gpasswd -a login_user mail

最後に、一旦ログアウトした後、再度ログインし直せば、設定は完了である。


$ logout

動作確認

動作確認は、mailコマンド(実体はHeirloom-mailx)を用いておこなう。
具体的には、端末上で以下のコマンドを入力すれば良い。


$ echo 'This is a test mail.' | mail -v -s 'sSMTP Test' hogepiyo@foo.bar.com

mailコマンドの詳細ログに、メール本文の後にSMTPの応答コード'250 OK'と'QUIT'が表示されていれば、設定は完了である。

参考にしたもの

  1. man ssmtp.conf
  2. SSMTP - ArchWiki
    https://wiki.archlinux.org/index.php/SSMTP
  3. SSMTPでメール送信しよう! - WebOS Goodies
    http://webos-goodies.jp/archives/50645131.html

雑記

  • sSMTPは、単にメールを送信するだけのシンプルな機能。
    • ちょっとした通知システムを作るのに便利そう。
    • テキストファイルを扱うスクリプトと組み合わせれば、色々と応用できそうな感じ。
  • sSMTPは、大半のLinuxでは公式リポジトリで提供されているみたい。また、BSDでも利用可能だそう。
  • sSMTPとは直接は関係ないのだけれど、cronを動かしてメールを送信する場合、環境変数に注意する必要がある。
    • cron上では$LANGの値が設定されない。そのため、全角文字が含まれるメールを送信すると、"Content-Type"が"Application/Octet-Stream"になってしまうことがある。
    • 詳しくは、こちらのサイトを参照する。(http://www.koikikukan.com/archives/2013/08/12-000300.php)
  • 現状だと、/etc/ssmtp/ssmtp.confにユーザIDとパスワードを記述してしまっている。セキュリティ上、よろしくない気がする。
    • パーミッションは640に設定しているので、いちおうは大丈夫。
    • 知識不足でよく分からないのだけれど、SMTPメールリレーという手法を使えば、/etc/ssmtp/ssmtp.confにIDとパスワードを記述しなくても良いらしい。


  • 設定方法まとめ記事を書くのが、全然上手くならない...
    • きっと、単純に練習量が足りないだけだと思う。
    • でも、まとめ記事を書くのは時間が掛かるので、あまり進んで書きたくもなかったりする。ぐぬぬ...

NeoBundleのキャッシュ機能を利用したVimの起動を高速化する設定法まとめ

Vimプラグインを管理するためのプラグイン、NeoBundleには、Version 3.0からプラグインをキャッシュする機能が追加された。
>> (https://github.com/Shougo/neobundle.vim/commit/fc8818ccbc2db471f4de3501a69c66d3bb798df0)
この機能を利用することで、プラグインを大量にインストールしたVimでも、高速に起動することが可能になる。


本記事では、NeoBundleのキャッシュ機能の設定方法について述べる。
また、Vimの起動がどの程度高速化するのか、実際に起動速度を測定し、検証した結果も述べる。


                  • -

※2015.5.12追記
NeoBundleのキャッシュ機能に関して、仕様が変更された。
(詳細: https://github.com/Shougo/neobundle.vim/commit/69cb3b2d3c159207e1a2620c51b6fe754289c841)


以下、仕様変更の内容を一部抜粋する。

  • 関数: neobundle#has_cache(), neobundle#has_fresh_cache()を廃止
  • コマンド: NeoBundleLoadCacheを廃止
  • 上記の関数/コマンドの代わりに、neobundle#load_cacheを追加


以上の項目は、本記事の内容にも影響を及ぼす。
よって、最新の仕様に合わせて、本記事の一部を修正した。

                  • -



環境

  • Vim (7.4.473)
  • NeoBundle (3.0)

設定方法

設定は、NeoBundleのキャッシュ機能を有効にする記述を、.vimrcに書込むだけである。

具体的には、.vimrcの適切な箇所に、以下の内容を記述する。
(Vimプラグインは、"$HOME/.vim/bundle"以下に格納されているものとする。)

if has('vim_starting')
    set nocompatible
    set runtimepath+=expand('$HOME/.vim/bundle/neobundle.vim')
endif
 
call neobundle#begin(expand('$HOME/.vim/bundle'))

call neobundle#load_cache  " キャッシュの読込み
 
" 以下、インストールするプラグインの指定
" NeoBundle自身
NeoBundleFetch 'Shougo/neobundle.vim'
 
" その他のプラグイン
NeoBundle 'hoge/piyo.vim'
      (中略)
NeoBundle 'foo/bar.vim'
" ここまで、インストールするプラグインの指定
 
NeoBundleSaveCache  " キャッシュの書込み
 
call neobundle#end()
filetype plugin indent on

利用方法

上記の設定を書込んだ後、初回の起動時にキャッシュの作成がおこなわれる。
次回以降の起動から、キャッシュを利用した高速起動が実行される。


キャッシュを明示的に作成したい場合は、:NeoBundleSaveCacheを実行する。
また、作成したキャッシュを削除したい場合は、:NeoBundleClearCacheを実行すれば良い。


キャッシュファイルのデフォルトの作成場所は、.neobundle/cacheである。
作成場所を変更したい場合は、"let g:neobundle#cache_file = '/path/to/cache_file'"を追記する。

検証

Vimの起動時間がどの程度短縮されたのかを調べるために、実際に検証をおこなった。
検証は、実機マシン上で、Vimの--startuptimeオプションを用いておこなった。
検証に使用したマシン環境は、以下の2つである。

マシン1:Lenovo Thinkpad X121e

  • CPU:AMD E-450 (2 core 2 thread, 1.65GHz)
  • メモリ:8GB (DDR3-1333)
  • ストレージ:SSD 256GB (CFD_CSSD-S6TM256NMPQ)
  • OS:Arch Linux (x86_64, Kernel 3.14.23-1-lts)

マシン2:Dell OptiPlex 9020



両マシンとも、同一の.vimrcを用いて計測をおこなった。
使用した.vimrcは、行数:2948(実効行数:980)、使用プラグイン数:120である。

検証結果

マシン1

$ vim -c 'NeoBundleClearCache | q' # キャッシュのクリア
$ vim --startuptime /tmp/cache_test -c q && tail -n 1 /tmp/cache_test | awk '{print $1}'
764.863
$ !-2:s/Clear/Save # キャッシュの有効化
$ !-2
561.097

マシン2

$ vim -c 'NeoBundleClearCache | q' # キャッシュのクリア
$ vim --startuptime /tmp/cache_test -c q && tail -n 1 /tmp/cache_test | awk '{print $1}'
6540.807
$ !-2:s/Clear/Save # キャッシュの有効化
$ !-2
5260.234
マシン1では、キャッシュ無: 764.863(msec)、キャッシュ有: 561.097(msec)、
マシン2では、キャッシュ無:6540.807(msec)、キャッシュ有:5260.234(msec)、という起動速度であることが判明した。
つまり、NeoBundleのキャッシュ機能を有効にすることで、マシン1では約200msec、マシン2では約1280msec、起動時間が短縮された。
以上の結果より、NeoBundleのキャッシュ機能によって、Vimの起動を2割程度、高速化できることを確認した。

参考にしたもの

  1. :help neobundle
  2. Vim - NeoBundle のキャッシュ機能 - Qiita
    http://qiita.com/hokorobi/items/0663da130f54bac3ce1a
  3. Big Sky :: vimmer必読!読み込みの遅いvimscriptを見つけ出す方法
    http://mattn.kaoriya.net/software/vim/20091104214557.htm

雑記

  • Vimの起動時間が1000ms以内の、元々起動が速い環境では、キャッシュの効果はあまり実感できないかも。

>> Cygwinのような遅い環境向け??

  • Cygwin環境のVim、重すぎ... いくらforkが遅いといっても、起動に数秒もかかってしまうのは勘弁してほしい。

Windows環境においてウィンドウをマウスオーバーでフォーカスしアクティブにしない設定法まとめ

大半のXウィンドウマネージャでは、ウィンドウをマウスオーバーでフォーカスだけをするようになっている。Windowsでは、通常はマウスオーバーではウィンドウをフォーカスしないが、"コンピュータの簡単操作センター"から、フォーカスするように設定できる。
しかし、この方法では、マウスオーバーするたびにウィンドウがアクティブ化(最前面に押出される)されてしまい、非常に操作しにくいことがある。この問題を解決するために、Xウィンドウマネージャの様に、ウィンドウをマウスオーバーでフォーカスするが、アクティブにはしない設定方法をまとめる。

環境

設定方法

レジストリ[HKEY_CURRENT_USER\Control Panel\Desktop]にあるUserPreferencesMaskの値を、"9F 3E 07 80 12 00 00 00"に変更すれば良い。
また、フォーカスが変わるまでの時間は、レジストリ[HKEY_CURRENT_USER\Control Panel\Desktop]にあるActiveWndTrkTimeoutの値で変更できる。


設定は、以下の手順で行う。

  1. レジストリキーのバックアップ
  2. レジストリキーの書込み
レジストリキーのバックアップ

まず、管理者権限のあるユーザアカウントでログインし、コマンドプロンプトを管理者で実行する。
次に、コマンドプロンプトで以下のコマンドを入力する。


> reg export "HKCU\Control Panel\Desktop" C:\reg_backup.reg

最後に、ドライブC直下に"reg_backup.reg"というバックアップファイルが出力されるので、任意の場所で保管しておく。

レジストリキーの書込み

まず、管理者で実行したコマンドプロンプトで、以下のコマンドを入力し、UserPreferencesMaskの値を変更する。


> reg add "HKCU\Control Panel\Desktop" /v "UserPreferencesMask" /t REG_BINARY /d 9F3E078012000000

次に、以下のコマンドでActiveWndTrackTimeoutの値を変更する。
時間(/d に続く数値)はミリ秒の任意の値を入力する。
(個人的には100くらいが丁度良いと思う。小さすぎる値にすると、タスクバー上のプレビューなどが使いづらくなるので。)


> reg add "HKCU\Control Panel\Desktop" /v "ActiveWndTrkTimeout" /t REG_DWORD /d 100
最後に、一旦ログオフして再度ログインする。

復旧方法

バックアップした"reg_backup.reg"ファイル上でメニューを開き、結合を実行する。

参考サイト

  1. Windows7 マウスオーバ フォーカス移動 - とあるシステムエンジニア徒然草
    http://k-shrimp-ebi.blogspot.jp/2012/04/windows7.html

OpenSSH公開鍵認証の設定方法 & 注意点メモ

Windows環境でLinuxサーバへ公開鍵認証方式でssh接続する際、設定をミスして、数時間も潰してしまった。
今後、同じミスを犯さないように、設定法を簡単にメモしておく。

環境

Windows(クライアント)側
Linux(サーバ)側
  • Debian Wheezy 7.6 (x86_64, kernel:2.6.32-042stab079.5)
  • openssh-server (1:6.0p1-4+deb7u2)

注意点

今回、以下の3点に気づかなくて、時間を無駄にしてしまった。以降、気をつける。

  • puttyegenで作成した公開鍵は、そのままではOpenSSHでは使用できない。

>> ssh-keygenを用いて、使用可能な形式に変換する必要がある。

  • authorized_keysの中身は、1行につき1公開鍵の対応関係にある。

>> この関係が何らかの形で壊れてしまうと、鍵認証がうまくいかない。

  • puttyegenで生成した公開鍵は、複数の行から構成されている。

>> 注意点1を忘れて、公開鍵を変換せずにauthorized_keysに書込んだ場合、認証がうまくできなくなる。

設定法

設定は、以下の手順で行う。

  1. 鍵ペアの生成 (クライアント側)
  2. 公開鍵の転送 (クライアント側)
  3. 公開鍵の形式変換 (サーバ側)
  4. 公開鍵の登録 (サーバ側)
鍵の生成

puttyegenを起動し、任意の暗号化法で鍵ペアを生成する。
生成した後、公開鍵と秘密鍵の両方を、任意の場所に保存しておく。

公開鍵の転送

セキュアな方法を使い、公開鍵をサーバに転送する。

公開鍵の形式変換

ssh-keygenを使い、公開鍵をOpenSSHで使用できる形式に変換する。


$ ssh-keygen -i -f putty_pubkey.pub > openssh_pubkey.pub

公開鍵の登録

変換した公開鍵を、authorized_keysに追記する。


$ cat openssh_pubkey >> $HOME/.ssh/authorized_keys

参考サイト

  1. 鍵交換方式による認証 - Penguin's campus note
    http://www14.plala.or.jp/campus-note/vine_linux/server_ssh/ssh_key.html

バージョン管理システムRCS使用法まとめ

バージョン管理システムRCS(Revision Control System)を使おう考えたので、使用方法をまとめる。

かなり古いツールで、機能は限定されているけれど、その分シンプルで、個人的には気に入っている。

概要

  • RCSの基本的な流れ
  • 初期登録
  • チェックイン
  • チェックアウト
  • 差分の確認
  • 変更履歴の表示
  • 特定リビジョンの取出し
  • RCSマーカーの抽出

RCSの基本的な流れ

   ファイルを管理対象に登録
        ↓
   →→→→→+
  ↑     ↓
  ↑  ファイルをロック
  ↑     ↓
  ↑     編集
  ↑     ↓
  ↑ ファイルをアンロック
  ↑     ↓
   ←←←←←

初期登録

以下のコマンドを実行し、ファイルをバージョン管理の対象として登録する。

ファイルのパーミッションは、登録時の値がベースとなるため、スクリプトに実行権限を付けたい場合は、初期登録前に付加しておく。

$ mkdir ./RCS
$ ci -i -l file

mkdir ./RCSは、実行しなくてもOK。

RCSディレクトリを作成した場合、バージョン情報を管理するRCSファイル(file,v)は、その中に格納される

RCSディレクトリを作成していない場合、RCSファイルは、fileのあるディレクトリに作成されるので注意。

ci -i -l fileを実行した際、ファイルに関する説明の入力を求められる。

(きちんと注意文も表示されるが、ここで入力するのはログメッセージではない点に注意)

RCS/file,v  <--  file
enter description, terminated with single '.' or end of file:
NOTE: This is NOT the log message!
>>

エディタedと同様に、'.'だけを入力し、改行することで、入力終了になる。

>> RCSテスト用ファイル
>> .
initial revision: 1.1
done

初期登録が終了したら、fileを編集することができる。

編集が終わったら、次のチェックインの手順へ進む。


チェックイン

ファイルの編集が終わり、変更内容をRCSファイルに更新する(チェックイン)場合は、ciコマンドを使う。

$ ci -l file

RCS/file,v <-- file
new revision: 1.2; previous revision: 1.1
enter log message, terminated with single '.' or end of file:
>>

ログメッセージの入力が要求されるので、変更の要約を入力する。

入力の終了は、初期登録時と同じく、'.'だけの行を入力する。

>> チェックインテスト
>> .
done

ログメッセージの入力後、ファイルはロックされ、パーミッションは644に変更される。

そのため、引続きfileの編集をおこなうことができる。

ファイルの変更をこれ以上おこなわない場合は、'-l'(-l:lock)の代わりに、'-u'(-u:unlock)オプションを付けてciコマンドを実行する。

$ ci -u file

'-u'オプションを付けた場合、ファイルはアンロックされ、パーミッションは444に変更される。


チェックアウト

RCSファイルから、fileを閲覧・編集用として取出す(チェックアウト)場合は、coコマンドを使う。

$ co file       # fileを閲覧用に取出す
$ co -l file # fileを編集用に取出す

閲覧用にチェックアウトした場合、fileのパーミッションは、444に変更される。

'-l'オプションを付けて、編集用にチェックアウトした場合、fileのパーミッションは、644に変更される。

特定のリビジョンを取出す方法は、特定リビジョンの取出し_ の項目で解説する。


差分の確認

リビジョン毎の差分を確認したい場合は、rcsdiffコマンドを使う。

rcsdiffは通常のdiffを呼出すので、diffの大半のオプションはそのまま使用できる。

オプション無しで実行する場合は、チェックアウト中のfileと、最新リビジョンの差分を表示する。

$ rcsdiff file
===================================================================
RCS file: RCS/file,v
retrieving revision 1.2
diff -r1.2 file
2a3
> hogehoge

'-r'オプションを使うと、特定のリビジョンとの差分を表示することができる。

$ rcsdiff -r1.1 file        # リビジョン1.1のfileと、チェックアウト中のfileの差分を表示する。
$ rcsdiff -r1.1 -r1.2 file # リビジョン1.1のfileと、リビジョン1.2のfileをの差分を表示する。

変更履歴の表示

変更履歴を表示したい場合は、rlogコマンドを使う。

履歴のタイムスタンプはデフォルトだとUTCで表示されてしまう。

そのため、'-zLT'(-zLT:zone LocalTime)オプションを付けて、localtimeで表示するようにしておく。

$ rlog -zLT file

毎回オプションを入力するのは面倒なので、シェルの設定ファイルでエイリアスしておくと便利。

alias rlog='rlog -zLT'

特定リビジョンの取出し

特定のリビジョンを取出したい場合は、以下の手順で作業をおこなう。

まず、ciコマンドでチェックインし、fileをアンロックしておく。

次に、'-r'オプションにリビジョン番号を付けて、coコマンドを使う。

$ ci -u file            # fileをチェックイン・アンロックする
$ co -r1.2 -l file # リビジョン1.2をチェックアウトする
RCS/file,v --> file
revision 1.2 (locked)
done

既存のfileを上書きしたくない場合は、'-p'オプションを付けて、表示内容をリダイレクトする。

$ co -r1.2 -p file > other_file

編集後、チェックインすると、ブランチが作成される。

今回の例では、リビジョン1.2をブランチ1.2.1としてチェックインする。

ブランチ1.2.1では、リビジョン番号は1.2.1.1から開始される。

$ ci -u file
RCS/file,v <-- file
new revision: 1.2.1.1; previous revision: 1.2
enter log message, terminated with single '.' or end of file:
>>

ブランチをチェックアウトする場合、リビジョン番号(もしくはブランチ)を明示する必要がある。

$ co -r1.2.1 -l file

ブランチを新たにトランクとしたい場合、ciとrcsコマンドを使う。

今回の例では、トランクのリビジョン番号は1.5であるので、ブランチを1.6として登録する。

$ rlog -h file | grep head
head: 1.5

作業は、ブランチのアンロック、トランクのロック、最新リビジョンのチェックイン、の順番でおこなう。

$ ci -u -r1.2.1 file        # まず、ブランチ1.2.1のfileをアンロックしておく
$ rcs -l -b file # 次に、トランクをロックしておく
RCS file: RCS/file,v
1.5 locked
done
$ ci -u file # 最後に、fileを最新リビジョンとしてチェックインする
RCS/file,v <-- file
new revision: 1.6; previous revision: 1.5
enter log message, terminated with single '.' or end of file:
>>
...

ブランチと並行してトランクを編集していた場合は、rcsmergeコマンドを使う。

rcsmergeの使い方は、マニュアル"man rcsmerge"を参照する。

(RCSでは、ブランチとトランクを同時進行でいじらない方が良いと思う。複雑なブランチを作るのに向いていないので。)


RCSマーカーの抽出

RCSでは、ファイル内に'$'で囲まれた特殊なキーワードが存在する場合、それを特定の情報に展開する機能を持つ。

特殊キーワードは、主に"$Id: rcs_tutorial.rst,v 1.6 2014/05/25 07:51:00 gin Exp gin $"が使用される。(他の特殊キーワードは、man identを参照)

特殊キーワードは、チェックイン時に自動的に展開される。

$ cat test.txt        # 特殊キーワード展開前
// $Id: rcs_tutorial.rst,v 1.6 2014/05/25 07:51:00 gin Exp gin $
hogehoge
...

$ ci -u test.txt
...

$ cat test.c # 特殊キーワード展開後
// $Id: rcs_tutorial.rst,v 1.6 2014/05/25 07:51:00 gin Exp gin $
hogehoge
...

デフォルトでは、時刻はUTCとして展開されてしまう点に注意。

ci実行時に'-zLT'オプションを付けておけば、localtimeとして展開する。

こちらもrlogと同様に、シェルの設定ファイルでエイリアスしておくと便利。

alias ci='ci -zLT'

展開した特殊キーワードのみを抽出したい場合は、identコマンドを使う。

identは、オブジェクトファイルやコンパイル後のバイナリにも使用することもできる。

(C言語の場合、文字列"rcsid"を使えば可能)

$ cat test.c
#include <stdio.h>
static const char rcsid[] = "$Id: rcs_tutorial.rst,v 1.6 2014/05/25 07:51:00 gin Exp gin $";

int main(int argc, char const* argv[])
...

$ ident test.out
test.out:
$Id: rcs_tutorial.rst,v 1.6 2014/05/25 07:51:00 gin Exp gin $


特定の言語使用時の注意点

PerlPrologなどでは、チェックイン時に、ソース内の変数変数が特殊キーワードとして誤認識され、展開されてしまうことがある。

また、LaTeXでは、逆に特殊キーワードがマクロとして処理されてしまうことがある。

以下、誤認識される恐れのあるキーワード一覧。

  • $Author$
  • $Date$
  • $Header$
  • $Id$
  • $Locker$
  • $Log$
  • $Name$
  • $RCSfile$
  • $Revision$
  • $Source$
  • $State$

LaTeXの場合は、スタイルファイル: rcs.styを使えば、簡単に解決可能。 (rcs.styはTeX Liveに含まれている)

以下、rcs.styの使用例。

プリアンブル部分でrcs.styを読込み、本文中でRCSマクロを使う。

\documentclass{jsarticle}
\usepackage{amsmath, amssymb}

\usepackage{rcs} % rcs.styを読込む

% ----- ここまでプリアンブル -----

\begin{document}
% --------- ここから本文 ---------
\RCS $Id: rcs_tutorial.rst,v 1.6 2014/05/25 07:51:00 gin Exp gin $ % "\RCS $keyword$"の形式で使う
\section{ほげ}
ほげほげ

\section{ぴよ}
ぴよぴよ

\end{document}


参考にしたもの

ドキュメント
  • man rcsintro
  • man rcs
  • man ci
  • man co
  • man rcsdiff
  • man rlog
  • man ident
  • man rcsfile

RCSのマニュアルは、けっこう充実している。

rcsintroは、基本的な使用法が簡潔にまとめられているので、一度は目を通しておくと良いと思う。


Webサイト
  • Ultimate Beginner's Guide to RCSRCS 超入門、〈http://vega.sra-tohoku.co.jp/~kabe/vsd/rcs/rcs.html

    RCSを使うための、必要最低限の操作法を紹介している。
    また、上記サイトは、中・上級向けのRCS管理テクニックも紹介している。
  • Nobwak's Lair:リビジョン管理rcsのすすめ(xxx.conf.20130829とかはもう止めよう)、〈http://april.fool.jp/blogs/?p=2195

    RCSを使うための、基本的な操作法を紹介している。
    このページの内容は、本記事と大体同じ。
  • www.naney.org:RCS FAQ(Japanese Page)、〈http://www.naney.org/comp/rcs/faq/

    RCSに関するよくある質問をまとめている。
    RCSを使っていて困ったことがある場合、殆どのケースはこのページを見れば解決できると思う。
    また、LaTeXにおける特殊キーワードの対策法は、こちらのサイトを参考にした。

雑感

  • 最低でも ci -uと co -lを知っていれば、なんとかなると思う

  • RCSは、シングルユーザかつ単一のファイルを扱う場合でないと使いづらい

=> 時代錯誤な仕様だけれど、シンプルで分かりやすいので、ちょっとしたファイルの管理用と割切って使うなら、逆に便利だと思う

  • RCSは、複雑なブランチを作ろうとすると、けっこう面倒

=> 複雑なブランチを作りたい場合は、素直に他のVCSを使ったほうが良いかもしれない

シェル変数まとめ

シェル変数を展開方法や、位置パラメータ、特殊変数の存在をよく忘れてしまうので、まとめておく。
変数の展開方法と特殊変数は、数が多いので有用そうなものだけまとめる。


ただ、今回まとめた内容は、主にシェルスクリプトで用いることになると思う。
憶えにくい、タイプ数の多い表記が沢山あるので。

動作を確認した環境

  • zsh (5.0.5)
  • bash(POSIXモード) (4.3.11)
  • mksh (49-1)
  • dash (0.5.7-4)

概要

  • シェル変数の展開
  • 位置パラメータ
  • 特殊シェル変数

解説

シェル変数の展開

シェル変数の値をセットする際、変数の使用状況・条件に応じて、セットする値や展開したときの表示を、変更することができる。
条件に応じて変数を設定する主な方法は、以下の通り。

  1. ${variable:=value}
  2. ${variable:-value}
  3. ${variable:?message}
  4. ${variable:+value}
  5. ${variable#pattern}
  6. ${variable##pattern}
  7. ${variable%pattern}
  8. ${variable%%pattern}
  9. ${variable/pattern/new}
  10. ${variable//pattern/new}

1~4の方法は、コロン':'を省略可能である。コロンを入れた場合、変数がこれまで未使用か、ヌルがセットされているときに、コロン以降の処理をおこなう。
コロンを省略した場合、変数がこれまで未使用のときのみ、コロン以降の処理をおこなう。


${variable:=value}
変数variableを展開する際、variableがこれまで未使用である、もしくはヌルである場合、valueを代入してから展開を試みる。

... # 変数VARは一度も使っていない
$ echo ${VAR:=hoge}
hoge # 変数VARは未使用であるが、値hogeが表示される
$ echo $VAR
hoge # 変数VARに値hogeが設定されている

${variable:-value}
変数variableを展開する際、variableがこれまで未使用である、もしくはヌルである場合、valueを代入せずに、valueをそのまま返す。

$ echo ${VAR:-hoge}
hoge # 表示される内容は = を使った時と同じ
$ echo $VAR
$ # ただし変数VARには値hogeが代入されていない
${variable:-value}は、値を変数に代入しないので、位置パラメータのように書込み禁止の変数に用いることができる。また、スクリプトのデフォルト値を設定する際にも有用である。

${variable:?message}
変数variableを展開する際、variableがこれまで未使用である、もしくはヌルである場合、messageを表示する。
${variable:?message}は、変数が未使用、もしくはヌルであるかどうかを確認するために使う。

${variable:+value}
変数variableに値が設定されている場合、設定されている値の代わりにvalueを表示する。variableの元の値は変更しない。また、variableが未使用、もしくはヌルである場合は、何もしない。

$ VAR=piyo # 変数VARに値piyoをセット
$ echo $VAR
piyo
$ echo ${VAR:+hoge}
hoge # 値piyoの代わりにhogeが表示される
$ echo $VAR
piyo # しかし元の値は変更されていない
${variable:+value}は、変数の値を変更せずに、展開した時の値を一時的に変えたい場合に使う。

${variable#pattern}
${variable##pattern}
変数variableの値が、patternで指定したグロッビングパターンにマッチする文字列で始まっていれば、マッチする部分を全て削除した値に展開する。variableの元の値は変更しない。
上記2つの違いは、文字列の照合方法。'#'の場合は最短マッチ、'##'の場合は最長マッチで照合をおこなう。


主に、パスの一部を抜出すときに使う。

$ TMPDIR=/home/hoge/tmp
$ echo ${TMPDIR##*/}
tmp

${variable%pattern}
${variable%%pattern}
変数variableの値が、patternで指定したグロッビングパターンにマッチする文字列で終わっていれば、マッチする部分を全て削除した値に展開する。variableの元の値は変更しない。
上記2つの違いは、文字列の照合方法。'%'の場合は最短マッチ、'%%'の場合は最長マッチで照合をおこなう。


上記の'#'と組合わせれば、ある文字列の中間部分だけを抜出すこともできる。

${variable/pattern/new}
${variable//pattern/new}
変数variableの値のうち、patternにマッチする部分をnewに置換した値に展開する。variableの元の値は変更しない。
上記2つの違いは、文字列の置換方法。'/'の場合は初めにマッチした部分のみを、'//'の場合はマッチすたもの全てを置換する。


簡易sedのように使えるので、様々な場面で役に立つ。




位置パラメータ

位置パラメータを表す変数は、以下の5種類。

  1. $0
  2. ${1..9}
  3. $#
  4. $*
  5. $@
  • 位置パラメータを使う上での注意点
    • 位置パラメータは、$0から$9までの、10個までしか扱えない
    • 10個より多くの位置パラメータを使いたい場合は、shiftコマンドを利用して、位置パラメータをずらしていく。

※ 例


$ cat shift_test.sh
#!/bin/sh
shift # 位置パラメータを左に1つずらす
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9
shift 3 # 位置パラメータを左に3つずらす
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9
$ sh shift_test.sh a b c d e f g h i j k l m n
hoge.sh b c d e f g h i j
hoge.sh d e f g h i jk l

$0
コマンド自身を表す。

${1..9}
第1, 第2, ..., 第9引数を表す。

$#
位置パラメータの個数を表す。
※ 例

$ cat param_test.sh
#!/bin/sh
echo $#
$ sh param_test.sh hoge piyo hogepiyo
3
$ sh param_test.sh "hoge piyo hogepiyo"
1

$*
$@
引数全体を表す。

$*と$@の大きな違いは、ダブルクォートで囲み、展開した場合の動作にある。
$*は、引数全体をダブルクォートで囲んだ状態にして展開する。$@は、引数1個1個をダブルクォートで囲んだ状態にして展開する。


また、位置パラメータが無い場合、$@はヌル、$*は""に置換される。




特殊変数

主要な特殊変数は、以下の4種類。

  1. $?
  2. $$
  3. $!
  4. $-

$?
コマンド実行時の終了ステータスを表す。ただし、バックグラウンドで実行させたコマンドに対しては無効。
終了ステータスは、プログラムに依存するが、大抵の場合は、正常終了:真(0)、異常終了:偽(0以外)の値がセットされる。

$$
現在動作しているコマンドのプロセスIDを表す。
プロセスIDは一意であるということを利用して、一時ファイルの命名など、ユニークな番号を付けたい場合に役に立つ。
※ 例

$ touch /tmp/hogehoge.$$

$!
バックグラウンドで実行させたコマンドのプロセスIDを表す。
waitコマンドと組合せて、バックグラウンドジョブが終了するのを待ちたい場合に役に立つ。
※ 例

$ rsync -a hoge piyo & # バックグラウンドでrsyncを実行する
... # rsyncが実行している間に、rsyncに依存しない処理をおこなう。
$ wait $! # rsyncが終了するまで待つ
... # rsyncの実行結果に依存する処理をおこなう

$-
シェル起動時オプション、およびsetコマンドを使って設定したオプションの一覧を表す。

※ 例


$ echo $SHELL
/usr/bin/dash
$ echo $-
smi # オプション:s, m, iがセットされている
$ set -o vi # オプション:V(vi-keybind)を追加
Vsmi # オプションにVが追加された





参考書籍

  1. Bruce Blinn、山下哲典(訳):入門UNIXシェルプログラミング 改訂第2版、pp.40-56、Softbank Creative(2003)
  2. 広瀬雄二:zshの本、pp.195-201、技術評論社(2009)

雑記

  • "=-?+"を使ったシェル変数の設定は、ややこしくて憶えにくい。参考書籍1にも書いてあるけれど、可読性を良くするなら、if文で代用したほうが良いかもしれない。
  • 変数の展開には、値の柔軟な変更ができる${variable:#pattern}もある。けれど、zshしか使えない上に、動作を変更できるフラグが非常に多いので、今回は割愛。