双六工場日誌

平凡な日常を淡々と綴ります。

Zabbix 2.0 のグラフの文字化けを直す、「alternatives」での日本語フォント設定方法

今更感がありますが、Zabbix 2.0 を入れる度にフォントの名前、パス、alternativesの書式を毎回忘れるのでメモ。環境はCentOS 6です。

「alternatives」を使ってZabbix 2.0 の文字化けを直す

Zabbix SIAのパッケージを使って、Zabbix 2.0 (zabbix-web)をインストールした直後は、「DejaVuSans」がグラフ描画用のフォントに指定されていて、Web画面を日本語化した場合、グラフ内の日本語が文字化けして「□」のような文字となってしまいます。これはグラフ描画用のフォントに日本語フォントが指定されていないためです。

f:id:sechiro:20130827025219p:plain

Zabbix SIAのパッケージを使って、Zabbix 2.0のインストールを行った場合、このグラフ表示用のフォントは「alternatives」という設定切替ツールで管理されています。インストール直後の設定を確認すると、以下のようになっており、日本語フォントが設定されていません。

$ alternatives --display zabbix-web-font
zabbix-web-font -ステータスは自動です。
リンクは現在 /usr/share/fonts/dejavu/DejaVuSans.ttf を指しています。
/usr/share/fonts/dejavu/DejaVuSans.ttf - 優先項目 10
現在の「最適」バージョンは /usr/share/fonts/dejavu/DejaVuSans.ttf です。

これに「IPA Pゴシック」を追加して、それに設定を切り替えることでグラフを日本語表示させることができるようになります。そのためには、以下のコマンドを実行します。

$ sudo yum install ipa-pgothic-fonts
$ sudo alternatives --install /usr/share/zabbix/fonts/graphfont.ttf zabbix-web-font /usr/share/fonts/ipa-pgothic/ipagp.ttf 1000

最後の引数の「1000」は優先度。「DejaVuSans」の優先度「10」より大きければ構いませんが、作業者が意図的に変更していることがあとからわかるようにここでは大きい値を設定しました。

以下のように、設定が変更されたことを確認します。

$ alternatives --display zabbix-web-font
zabbix-web-font -ステータスは自動です。
リンクは現在 /usr/share/fonts/ipa-pgothic/ipagp.ttf を指しています。
/usr/share/fonts/dejavu/DejaVuSans.ttf - 優先項目 10
/usr/share/fonts/ipa-pgothic/ipagp.ttf - 優先項目 1000

設定変更は、これで完了です。Webブラウザからグラフを確認してみてください。「□」のところが、日本語表示となっているはずです。

f:id:sechiro:20130827025240p:plain

「alternatives」の仕組み

ここまでで設定変更としては十分ですが、せっかくなので「alternatives」コマンドのことも補足として書きたいと思います。

「alternatives」は、複数の設定を都度入れ替えて使えるようにする仕組みです。内部では、設定された内容でシンボリックリンクの張替えを行う。今回の設定の後、変更されたシンボリックリンクの内容を確認すると以下の通りとなっていました。*1

$ ll /usr/share/zabbix/fonts/graphfont.ttf
lrwxrwxrwx 1 root root 33  827 02:15 2013 /usr/share/zabbix/fonts/graphfont.ttf -> /etc/alternatives/zabbix-web-font
$ ll /etc/alternatives/zabbix-web-font
lrwxrwxrwx 1 root root 38  827 02:15 2013 /etc/alternatives/zabbix-web-font -> /usr/share/fonts/ipa-pgothic/ipagp.ttf

「alternatives」が書き換えているシンボリックリンクを直接「ln」コマンドを使って書き換えても同等の設定は可能です。ネットを検索した限りだとその手順も多いですが、パッケージが「alternatives」を使っているので、その流儀に従う方がベターだと思います。

ちなみに、ターミナルで「alternatives」とだけ打つと、以下のように新規設定の方法が表示されますが、かなり直感的ではありません…。

alternatives --install <リンク> <名前> <パス> <優先度>

ここで表示されているそれぞれの引数の意味は以下の通りです

  • <リンク>は、管理したい設定ファイルのパスです。今回はZabbixグラフ描画用フォントファイル「/usr/share/zabbix/fonts/graphfont.ttf」です。
  • <名前>は、alternatives上での設定管理名で、今回は「zabbix-web-font」*2
  • <パス>は、追加する設定ファイルへのパスで、今回は新たにインストールした「/usr/share/fonts/ipa-pgothic/ipagp.ttf」です。
  • <優先度>は、複数の<パス>が設定されている場合の優先度。値が大きいほうが優先的に使用される。今回はもともとの「DejaVuSans」に「10」が設定されていたので、追加した「IPA Pゴシック」に「1000」を指定して、そちらが優先的に使われるようにしました。ただし、優先度にかかわらず、以下に紹介する方法で、直接使用する<パス>を設定することもできます。

また、今回行った設定を元に戻したい場合は、以下のコマンドを使います。コマンドを実行すると、対話的に設定を選ぶことができます。追加設定時は面倒ですが、その後の切替は楽ですね。

$ sudo alternatives --config zabbix-web-font

設定の際の参考になれば。それでは。

追記: 「zabbix-web-japanese」 をインストールすればよいとの情報をいただきました。

@ さんから、以下の情報をいただきました。

このパッケージは、Zabbix SIAのリポジトリに含まれているファイルで、中身を確認したところ、以下のコマンドで「alternatives」の設定を追加して、日本語フォントを設定してくれるもののようです。

/usr/sbin/update-alternatives --install /usr/share/zabbix/fonts/graphfont.ttf zabbix-web-font /usr/share/fonts/vlgothic/VL-PGothic-Regular.ttf 20

以下のコマンドでインストールできます。

$ sudo yum -y install zabbix-web-japanese

インストールして、結果を見たところ、僕の環境では以下のような設定がなされました。

$ alternatives --display zabbix-web-font
zabbix-web-font -ステータスは自動です。
リンクは現在 /usr/share/fonts/ipa-pgothic/ipagp.ttf を指しています。
/usr/share/fonts/dejavu/DejaVuSans.ttf - 優先項目 10
/usr/share/fonts/ipa-pgothic/ipagp.ttf - 優先項目 1000
/usr/share/fonts/vlgothic/VL-PGothic-Regular.ttf - 優先項目 20
現在の「最適」バージョンは /usr/share/fonts/ipa-pgothic/ipagp.ttf です。

優先度「20」で「VL-PGothic-Regular」の設定が追加されていますね。ただ、手動で設定したものより優先度が低いので、そのままだと設定が変わらず。以下のコマンドを実行して、「3」を選ぶと追加でインストールした設定に切り替えることができました。

$ sudo alternatives --config zabbix-web-font

3 プログラムがあり 'zabbix-web-font' を提供します。

  選択       コマンド
-----------------------------------------------
   1           /usr/share/fonts/dejavu/DejaVuSans.ttf
*+ 2           /usr/share/fonts/ipa-pgothic/ipagp.ttf
   3           /usr/share/fonts/vlgothic/VL-PGothic-Regular.ttf

Enter を押して現在の選択 [+] を保持するか、選択番号を入力します:3

*1:/etc/alternatives以下にシンボリックリンクが貼られていれば、そのファイルはalternativesに管理されているファイルということになります。

*2:これが/etc/alternatives以下に作成されるシンボリックリンクの名前になっています。そのため、変更対象の設定名がわからない場合は、/etc/alternativesのシンボリックリンクファイル名から名前を調べることができます

bashのプロセス置換機能を活用して、シェル作業やスクリプト書きを効率化する

@ さんが「シェルスクリプトでハマった件→【募】ステキな回避方法」でお題を出されていて、それに回答してみました。

その内容はリンク先を見てもらうとして、回答の中で使ったbashのプロセス置換について書かれた記事をあまり見ないので、回答で使ったプロセス置換のことをエントリにしてみたいと思います。

最初に注意点ですが、プロセス置換の機能は、bashzsh*1の機能でPOSIX互換の機能ではありません。そのため、使用時には、対応していないシェルでは使えませんし、bashで使う場合も /bin/sh ではなく /bin/bash を明示的に指定する必要があります。たとえば、プロセス置換を使ったスクリプト「script.sh」に対して"$ bash script.sh" というコマンドは成功しますが、"$ sh script.sh" というコマンドは失敗します。この辺りの違いは「/bin/sh と /bin/bash の違い」を見てみてください。

さて、本題のプロセス置換ですが、"man bash” を見ると以下のように書かれています。

Process Substitution

Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files. It takes the form of <(list) or >(list). The process list is run with its input or output connected to a FIFO or some file in /dev/fd. The name of this file is passed as an argument to the current command as the result of the expansion. If the >(list) form is used, writing to the file will provide input for list. If the <(list) form is used, the file passed as an argument should be read to obtain the output of list.

When available, process substitution is performed simultaneously with parameter and variable expansion, command substitution, and arith-metic expansion.

これだけではよくわからないと思うので、出力対象として使った場合、入力対象として使った場合の使用例をご紹介します。

出力対象としてプロセス置換を使う >(list)

出力対象にプロセス置換を指定すると、例えば以下のようなことができます。僕としては、一番最初の例をよく使います。

スクリプト出力のすべてをログに取る*2

#!/bin/bash
# 以降の出力はすべて画面に出力されるとともにログファイルにも記録される。
exec 1> >(tee -a stdout.log)
exec 2> >(tee -a stderr.log >&2)
(何か処理)

標準エラー出力の内容をフィルタする*3

#!/bin/bash
exec 2> >(grep -v "exclude" > &2)
(何か処理)

teeの分割先に指定

cat inputfile | tee >(grep -v exclude > outputfile)

入力対象としてプロセス置換を使う <(list)

こちら側の使い方では、処理済みテキストを渡したい場合に汎用的に使うことができます。いくつか例を挙げます。

diffの入力対象に処理済みテキストを渡す

一番よくある使い方はdiffと組み合わせて使う方法です。diffは、入力対象としてファイルのみを対象としているため、通常のパイプで処理済みテキストを渡すことができません。プロセス置換を使うことで、コマンドで処理した結果同士をdiffで比べることができます。

diff <(grep -v "exclude" inputfile) <(sed -e 's/a/b/' inputfile)

inputfileの中で、"exclude"という言葉が入っている行を除外してWhileループを回す

プロセス置換は、あたかもファイルであるかのように扱うことができるので、Whileループにも渡すことができます。たとえば、以下の2つは同等の内容になります。

  • プロセス置換を使わない方法
cat inputfile | grep -v "exclude" > newfile
while read line
do
    echo $line
done <newfile
  • プロセス置換を使う方法
while read line
do
    echo $line
done < <(cat inputfile | grep -v "exclude")

プロセス置換を使うとこのように一時ファイルへの書き出しを行う必要がなくなり、処理後に削除するなどといった扱いを気にする必要がなくなります。

bash プロセス置換」などのワードで検索するとほかにもいろいろ例が出てくると思います。どうしても一時ファイルを書きたくない、という場合以外は、必ず使わなければいけない機能ではないですが、覚えているとスクリプトをシンプルかつ見通しよく書ける場合があります。

僕も応用例にはあまり詳しくないので、ほかにいい活用例があれば教えてもらえると嬉しいです。

<追記>

プロセス置換を使ったタイムスタンプ付きフィルタの例として、OpenStack開発環境のDevStackにちょうどいい例があるので、そちらもご紹介。DevStackのスクリプトは、bashの便利機能を多用しているので非常にいいサンプルになります。 ただ、bash固有の機能を知らないとどこでログにタイムスタンプが付けられているのかを理解するのが難しい…。

以下は「stack.sh」の該当箇所のみの引用ですが、スクリプト本体にはコメントがないので、上記のサイトの解説から引っ張ってコメントにしています。

#Copy stdout to fd 3
    exec 3>&1
    if [[ "$VERBOSE" == "True" ]]; then

#Redirect stdout/stderr to tee to write the log file
        exec 1> >( awk '
                {
                    cmd ="date +\"%Y-%m-%d %H:%M:%S \""
                    cmd | getline now
                    close("date +\"%Y-%m-%d %H:%M:%S \"")
                    sub(/^/, now)
                    print
                    fflush()
                }' | tee "${LOGFILE}" ) 2>&1

#Set up a second fd for output
        exec 6> >( tee "${SUMFILE}" )
    else

#Set fd 1 and 2 to primary logfile
        exec 1> "${LOGFILE}" 2>&1

#Set fd 6 to summary logfile and stdout
        exec 6> >( tee "${SUMFILE}" /dev/fd/3 )
    fi

<さらに追記 8/18>

ブコメで以下のコメントをもらったので、ここで出しているwhileループの例について補足します。

whileループのところ、直接 cat inputfile | grep -v exclude | while read line ~~ すればいいのでは?

僕が出していた例は、確かにコメントでいただいたものでも結果は変わりません。ただ、もともとのお題がパイプに伴う変数の扱いの問題で、コメントでいただいたようにパイプでつないだ場合、「ループ内で変数を変更してもそれがメインシェルの変数に反映されない」*4という問題に引っかかります。なので、ここではパイプを使わない場合の例を書きました。

たとえば、以下のスクリプトを実行してみます。

#!/bin/bash
var="first"

cat inputfile | grep -v exclude | while read line
do
    # ループの中で変数書き換え
    var="second"
done
echo $var # whileループ内での変更が反映されて、"second"が出るはず・・・?

while read line
do
    # ループの中で変数書き換え
    var="second"
done < <(cat inputfile | grep -v exclude)

echo $var # 上と同様の結果???

2つのループの違いは、パイプかプロセス置換での擬似的なファイル入力かだけですが、こちらの出力結果は、以下のようになります。

first
second

前者の場合は、var="second"への変更がWhile内部だけでしか有効にならないため、その外にあるvar変数に反映されません。一方、後者ではwhileループの中で変数変更が反映されています。*5この辺りはお題のエントリの解答編に詳しく書かれているので、そちらをご参照ください。

*1:プロセス置換は、zshでも使えるようですが、僕自身はzsh使いではないので、ここでは触れません

*2:プロセス置換を使わなくてもファイルに標準出力と標準エラー出力をリダイレクトして、それをtailすることで実現できますが、そうすると別途tailのプロセスの扱いを考えたりする必要があって手間がかかります。

*3:これがhirose31さんの日記にコメントしたものです

*4:この原因は、サブシェルの起動によるものだと説明されることが多く、僕もこれまでそう思っていましたが、お題のブログへのコメントに「bash (や POSIX sh) は、コマンドパイプラインの変数値変更はそのコマンドラインローカルになるから」ということではないかということが書かれていました。自分の手元で実験した限りでは、確かに指摘の通りで、サブシェルを使わない場合でも同じ現象となりました。

*5:一時ファイルを使った場合もプロセス置換と同様の結果になります。

no_proxy にネットワークアドレスとかワイルドカードを指定しても期待通りに動かない、でどうするかというお話

世の中には、イントラなど直接インターネットに繋ぐことができず、プロキシ経由でしかインターネットに出られない環境で、検証をやっている人も多いと思います。 僕自身もそういうことが多く、検証環境を作り直す度にプロキシ設定不備で無駄にハマったりと時間をとられることが度々ありました。

それで、この際、ちゃんとまとめておくかと思ってブログを書き始めたのですが、ぐぐってみると全く同じような問題意識で書かれたブログ記事があって、全般的な内容はそちらに書かれていたので、落ち穂拾い的に no_proxy の設定だけ補足を書いてみます。

プロキシ設定についての全般的な内容が書かれているブログはこちら。

上記のブログでは、見落としがちで面倒なsudoの設定や、gitの設定まで網羅されているので、大概のプロキシ設定はこの内容で何とかなると思います。*1

ということで、プロキシ設定全般の話は、そちらを参照してもらえばよくなったので、落ち穂拾いとして、こちらには書かれていない no_proxy のハマりどころだけ取り上げたいと思います。

Linuxで、プロキシを設定するのに一番簡単な方法は、以下のように環境変数でプロキシ設定をする方法です。これを設定していると多くのプログラムで、指定されたプロキシを使うようになっています。

export http_proxy=http://proxy.example.com:8080/
export https_proxy=http://proxy.example.com:8080/

ただ、この方法だとそのシェルから実行されるプログラムでのHTTP(S)アクセスがすべてプロキシ経由となってしまうため、検証環境内部で動いているサービスへのアクセスにもプロキシを使おうとしてしまいます。 それを避けるために設定するのが「no_proxy」環境変数です。たとえば、以下のように設定します。

export no_proxy=127.0.0.1,localhost,192.168.1.1

たとえば、ログインシェルからクライアント起動して検証環境内部のコンポーネントに直接HTTP通信を行い、同時に、最新のソースコードやパッケージはプロキシを通じて外部から取得したい場合*2には、このように「no_proxy」まで設定してやる必要があります。

ここまでは上記のブログにも書かれている内容です。

ただ、この際の「no_proxy」の仕様が曲者で、僕が確認したプログラムではここに設定できるのは「IPアドレス」もしくは「ドメイン名」のみとなっており、プロキシを経由したくないIPアドレスを複数指定する場合は、IPアドレスをひたすらカンマ区切りで列挙する必要があります。たとえば、内部サーバへの接続の際にIPアドレスをそのまま使っている場合、プロキシ経由してほしくないIPアドレスのすべてをここに書き下すことになります。 たとえば"192.168.0.0/24"とか"172.16.0.*"といった、ネットワークアドレスでの指定やワイルドカードでの指定は期待通りの動作になりません。

参照サイト

ちなみに、ここの回答で根拠になっているドキュメントは、wgetのmanページの記述のようです。まさに環境変数そのものの仕様を定めたものは見つからず…。環境変数の扱いは、それぞれのアプリケーションが独自に扱いを決めていて、標準仕様はないということかな。*3*4

ちょっとそれましたが、このような仕様のため、参照サイトでは以下のように、一つ前のブログで書いたようなブレース展開をしたカンマ区切りリスト作成でのno_proxy指定が紹介されています。bashをログインシェルにしている環境で、かつ、/etc/environment ではなく、/etc/bashrc 等に書かないと期待した動作にならないと思いますが、参考までに。

printf -v no_proxy '%s,' 10.1.{1..255}.{1..255};
export no_proxy="${no_proxy%,}";

また上記の例ではもう一つ注意点があり、この例のとおりに「no_proxy」を設定すると、環境変数があまりに長くなりすぎて、以下のようなエラーでvimなどが起動できなくなるという問題があります。なので、とにかく使いそうなIPを全部入れるのではなく、必要最低限の範囲で設定しないといけません。以下のようなエラーが出るようになってしまった場合は「unset no_proxy」で、一旦変数を削除したあとに再設定するのが吉です。

$ vim
-bash: /usr/bin/vim: 引数リストが長すぎます

ちなみに、ブレース展開を使った設定では一つ前のブログのもう一つの手法を使って、以下のようにすることもできます。こちらもbashオンリーです。

no_proxy=$(echo 192.168.1.{1..5})
export no_proxy=127.0.0.1,localhost,${no_proxy// /,}

どちらにしても、環境変数に長大なIPリストができてしまうのは避けられませんが、、、

あまりに長くなる場合は、ドメイン名での振り分けを聞くようにするとか、別の方法を考えたほうがよさそうです。

このネタはこんなところで。

*1:こちらのブログでは /etc/environmentでシステムワイドの環境変数を設定していますが、僕自身はこのファイルでの設定に馴染みがないので、/etc/profileや/etc/bashrcでシェル向けに環境変数を設定しています。/etc/profileや/etc/bashrcはシェルスクリプトなので、スクリプトでの処理結果やbash拡張機能を使った出力結果を環境変数に指定することができます。一方、/etc/environmentは、スクリプトではなく、pam_env.soが読み込むデフォルト環境設定ファイルです。

*2:具体的には社内にOpenStack検証環境を作るときとか

*3:たとえば、こんな記事も見つけました。「HTTP::Tiny 0.32で no_proxyがサポートされました」 http://d.hatena.ne.jp/syohex/20130622/1371884244

*4:環境変数名も大文字、小文字の両方があって、最初に紹介したブログでは両方とも指定していますね。

bashのブレース展開を使ってカンマ区切りリストを作る

bash操作のTipsメモです。

bashには、ブレース展開というブレース({}のカッコのこと)の中身を一定の法則で展開して、半角スペース区切りのリストにしてくれる機能があります。

例えば、以下のように使うことができます。

$ echo 192.168.1.{1,3}
192.168.1.1 192.168.1.3
→ブレースの直前の文字列にカンマで区切った文字列を組み合わせたリストに変換

$ echo 192.168.1.{1..5}
192.168.1.1 192.168.1.2 192.168.1.3 192.168.1.4 192.168.1.5
→数値の連番の場合は ".." で数値を繋ぐとその範囲で数値を変化させたリストに変換

$ echo /opt/{app,db}/{data,conf}
/opt/app/data /opt/app/conf /opt/db/data /opt/db/conf
→複数のブレースがある場合は、そこに入っている値の組み合わせでのリストを出力。
これによってまとめて複数のディレクトリを作ったりすることができる。

「ブレース展開」でググると、いろいろな使い方が紹介されているのを見つけることができますが、例えば、 http://d.hatena.ne.jp/xr0038/20111221/1324446298 では使い方の具体例がいろいろ紹介されています。

これは非常に便利な機能なのですが、値の区切るデリミタが必ず半角スペースになってしまうので、例えば、カンマ区切りでホスト名が欲しい時*1などは、得られた結果を素朴に sed で置換していました。*2

sedを使った素朴な変換の例
$ hostlist=$(echo 192.168.1.{1..5} | sed 's/ /,/g')
$ echo $hostlist
192.168.1.1,192.168.1.2,192.168.1.3,192.168.1.4,192.168.1.5

これ自体は汎用的な方法で、特に問題があるわけではありませんが、せっかくbash組み込みの機能を使っているので、sedを使わないでできる方法を調べてみました。

bash組み込み機能を使うと、以下の方法で半角スペースからカンマへの変換ができます。

bashの変数展開時のパターンマッチを使ったやり方
$ hostlist=$(echo 192.168.1.{1..5})
# ${変数名//パターン/文字列/} とするとパターンに一致するすべての部分を文字列で置換したものを返す
$ echo ${hostlist// /,}
192.168.1.1,192.168.1.2,192.168.1.3,192.168.1.4,192.168.1.5
bash組み込みのprintfコマンドを使った方法
# bash組み込みのprintfコマンドは "-v 変数名" でその変数に出力結果を格納することができる
$ printf -v hostlist '%s,' 192.168.1.{1..5}

# ${変数名%パターン} とすると、変数末尾をパターンマッチし最短マッチ部分を削除された結果を出力する
# それを利用して最後の余分なカンマを削除する
$ echo ${hostlist%,}
192.168.1.1,192.168.1.2,192.168.1.3,192.168.1.4,192.168.1.5

前者はsedにも近い書式のパターンマッチで比較的覚えやすく、値を使う際にデリミタを切り替えて使えるというメリットがあります。一方、後者は printf が /usr/bin/printf ではなく、bash組み込みコマンドの方になっている*3という罠があるのに加えて、変数展開も独自書式なので、この場合はあまり向いていなさそうです。

bashのパターンマッチには、ここで使った以外にもシェルを使った作業を効率的に勧められるようなものが揃っています。

参考サイト

例としては、パターンマッチと同じ方法を使ったディレクトリ名、ファイル名が挙げられているのをよく見ます。

$ filepath=/path/to/file.txt
$ dir=${filepath%/*}        # => /path/to
$ filename=${filepath##*/}  # => file.txt

ただ、僕としてはディレクトリ名、ファイル名の取得では、専用コマンド dirname, basename を使う方がお勧めです。bash依存にならずに済みますし、これらのコマンドはオプションを使うことで、拡張子を除いたファイル名を取り出すといった操作がより直感的にできるからです。

公開されているスクリプトを読んだ時に、この書き方が出てくることがあるので、こういう書き方があるのか、ぐらいに覚えておくのがいいと思います。*4

今日のところは、ここまでで。

*1:例えば、Fabric の -H オプションでホスト名の一覧を渡すとき

*2:手元で実験した限りでは、IFSを変えてもデリミタは半角スペースのままでした。これを変更できる方法を知っている方がいれば教えてもらえると嬉しいです。

*3:type printfで調べられます

*4:このエントリのメインで挙げている例は、そもそもbash組み込みのブレース展開との組み合わせなので、そこでbash依存になるのは割り切って使っています。

シェルスクリプトのコーディングスタイル・コーディング規約について考えてみる

シェルスクリプトのコーディングスタイルについて調べ物をしたので、その情報源の一覧と今の感想のメモを書いてみます。

上記のページの最初には「ここに書かれている内容は、あくまで筆者の好みでありほぼ完全に主観」と書かれていますが、この内容は規約としてどこでも採用すべき内容だと思います。また定数には大文字の変数名を使うというガイドラインですが、自分で書く場合、環境変数も大文字変数に加えます。
好みがあるとすれば、インデントの幅ぐらいでしょうか?
ここではインデント幅は半角スペース2つが推奨されていますが、個人的には半角スペース4の方が好みです。

Pythonのコーディング規約PEP 8を見ても、タブとスペースを混ぜるな、スペースの方が人気があるので推奨というぐらいの書き方で、明確にインデント幅を指定していないので、インデント幅まではスタイルに含めないのがいいんでしょうか。

Tabs or Spaces?
    Never mix tabs and spaces.
    The most popular way of indenting Python is with spaces only. 

ちなみに、Pythonライブラリではインデント幅は「4」が多いらしく、僕もPythonのインデント幅は4。シェルスクリプトのインデント幅もそれに合わせているという面が強いです。



以下は、参考になりそうな海外の情報(英語)です。

  • SIGNAL Trapを使ったロックファイル削除などについても書いてあるコーディングスタイル。

シグナルを使った終了処理はこういう感じがよさそうです。bashの擬似シグナルは便利だけど、広く使うスタイルとしては入れない方がいいかなと思います。

  • PDF。SIGNAL Trapを使った一次ファイルの削除方法やテスト手法にも言及しているコーディング規約のドキュメント。


以下は、近年のIT勉強会クラスタの議論から。



また、反応としてはだいぶ遅いですが、上に紹介した情報の中の @ さんの「シェルスクリプトを書く際に気を付けていること8箇条」の補足を書いたに若干コメントしたいと思います。

  • スクリプトのオプション指定について

上記のエントリに、以下の2つを比較して、前者の方がコードが減るのでベターというコメントがありましたが、僕としては後者の書き方を使っています。

#!/bin/sh -ue
#!/bin/sh
set -ue

というのも、以下のようにスクリプトを実行した場合、

sh test.sh

前者は、/bin/sh 、後者は/bin/sh -ue でコマンドが実行され、後者の方が自分の直感に近いからです。
例えば、スクリプトのデバッグのために、一時的に-xオプションを付けてコマンド実行する場合、以下のように実行することが度々あると思うのですが、その際にば前者は、/bin/sh -x 、後者は/bin/sh -xue となってしまい、混乱を招くように思います。*1

sh -x test.sh

なので、スクリプトのオプションはsetコマンドで別の行にて定義するのがいいのかなと。Perlで言うと「use strict; use warnings;」みたいな感じで「set -ue」。*2

上記のエントリではShebangでの「#!/bin/sh」と「#!/bin/bash」で違いがあるのか、という話も出てきますが、それについては別のエントリに書いています。結論からいうと、多くの場合で問題になりませんが、微妙に動作が異なります。

/bin/sh と /bin/bash の違い



今のところの結論として、最初に紹介しているページの内容に加えて「set -ue」、必要に応じてSIGNAL Trapの使い方を共通認識とするのがいいのかなと思っています。


とはいえ、スタイルや規約には一長一短あるので、このエントリを見てくれた方もリンク先を見て自分に馴染むところを取り入れてもらうのがいいかなと思っておりますです。

*1:逆にshコマンドを明示的に指定する場合には、オプション指定は一旦解除したいという目的を持って前者を書くという考え方もありうるとは思いますが。

*2:ちなみに -ue と書いているのは、自分としてはeオプションの方が外す頻度が多いため、それを後に書く癖がついています。これは、どちらが先でもよいと思います。

「メイド喫茶愛好家の集い」は、秋葉原文化の歴史的転換点(になるはず)

最近、「エヴァンジェリスト」と言われると「メイド喫茶エヴァンジェリスト」のことを指すようになってきた気がしてならないせちろーです。

さて今日、2013年5月11日はメイド喫茶クラスタにとって、非常に重要なイベントの日でした。
その名も「メイド喫茶愛好家の集い」。
この10年の秋葉原のメイド喫茶を引っ張ってきた伝説的なメイド4名が一同に介する史上初のイベントです。募集当日、数時間で席が埋まってしまうほどの人気イベントでしたが、募集直後に見つけることができたため、僕は運良く参加することができました。


このメンバーがどのぐらいすごいのかは、メイド喫茶クラスタ以外には伝わりにくいところがあるのですが、あえてほかの言い方をすれば日本の主要なベンチャー企業トップが一同に会した、とでも言ったらいいでしょうか。メイドさんを3次元の存在にたとえてしまうと大事なことが抜けおちてしまうような気もしますが…。*1
実際に@ほぉ~むカフェのhitomiさんはメイドから@ほぉ~むカフェを運営するインフィニアの取締役社長になり、現役メイドでもありながら競争の激しい秋葉原で5店舗を経営する経営者でもあります。*2



今回のイベントは緩い感じのタイトルとは裏腹に、そういった伝説的メイドの方々と参加者とが、これからのメイド喫茶、これからの秋葉原、そして、それらの文化をこれからどのように育て、どのように世界に発信していくかをテーマに語り合うというガチイベントでした。綺麗な言い方をすると、ボトムアップ型での街づくりを考えるイベントですね。
主宰のたかとらさん(@)、やんさん(@)はすごく真面目で人望のある方で、準備も周到。参加者は事前に自己紹介文を書き、当日、会場で名札と参加者リストが配られるという徹底ぶりです。


そもそもメイド喫茶がなかったころ、「萌え」というフレーズが今のように使われなかったころから、メイドを始め、新たな道を切り開いてきたみなさんのお話はいずれも聴き応えがあり、しかも、これまでのメイドとしての心遣いも感じられるすごくいい話が多かったです。話のスケールも自分の店がどうこうではなくて「世界に対して〜」「30年続けて文化をつくる」ぐらいの視野の話です。
また、参加者も一緒に文化を作り上げる仲間*3として、これまでにメイド喫茶に来たことがない人に、様々なテーマ・コンセプトのメイド喫茶があることを伝え、お店に来やすい雰囲気を作っていくのかを真剣に考えていました。


こういう感じのかなり本気なイベントではありましたが、やはりメイド喫茶愛好家の集いということとで、最後は「萌え萌えじゃんけん」の生みの親であるhitomiさんの指導のもと、ありささんとみんなで萌え萌えじゃんけんをやるという完璧な締め(笑)

写真はとれなかったので、司会だったササキチさん(@)さんのつぶやきを拝借します。リンク先のブログから麗しい伝説のメイドの姿をご覧ください。

記者の方も入っていたので、詳細な記事が出るのを期待して待っています(・∀・)


30年後の日本史の教科書にはこのイベントが秋葉原文化の歴史的転換点として載るようになり、プロジェクトXばりののドキュメンタリーとしてまとめられる日が来るのを妄想する次第です。



お店に興味があって行ってみたい方がいれば、もちろん僕もご一緒させてもらいますので声かけてくださいまし。

ーーーー
5/12 7:38 追記
ほかの方の報告ブログやエリスさんの脳内スチルなどです。




*1:具体的に人の名前で例えるとややこしいので控えますが。

*2:できればメイドさんを全員紹介したいのですが、それを書くのは自分の力に余るのでご勘弁くださいm(__)m

*3:メイドさんから「プロのお客さん」と呼ばれていたことは秘密ですw

「hbstudy #44 ベンチマーク勉強会(基礎編) 現場で役立つベンチマークのススメ」に行ってきた。

こんにちは。
最近、どんなブログを書いても「どんまいこの花嫁修業」には勝てない気がしているせちろーです。とはいえ、最近まじめにやっていない勉強会参加報告ブログを書いてみたいと思います。


さて、5月10日は「hbstudy #44 ベンチマーク勉強会(基礎編) 現場で役立つベンチマークのススメ」が新宿でありました。*1講師は、日本国内では数少ない(らしい)職業的ベンチマーカーの宮原さん@

内容は、宮原さんがベンチマークの裏話や機材、ベンチマーク手法について、ニヤニヤしながら楽しそうに2時間半語り倒すという非常にマニア向けな内容です。(笑)
ですが、そんな内容に惹かれて集まった参加登録者は開催時点で122人。スタッフも入れたら、当日は130人はいたんじゃないでしょうか。
これだけの人数が集まったのは、ベンチマークはインフラエンジニアの基礎技術の一つだと思いますが、一般的な確立された手法がなく、ベンチマークの第一人者である宮原さんが話す内容に注目が集まったからだと思います。かく言う、僕もベンチマークの度に試行錯誤している身です。


勉強会の資料はこちらにアップされているので、内容全般はそれを見てみてください。ベンチマークの基本的な考え方、ハマりどころ、具体的な手法が網羅された非常に良い資料なので、エンジニア必読の資料だと思います。また、今回はベンチマーク勉強会とも共同開催となっていましたので、ベンチマーク勉強会の資料も一緒にアップされています。

http://connpass.com/event/2366/?disp_content=presentation#tabs

会場では、資料には載せられないような裏話もちらほらありましたが、それが聞けるのは直接会場にいた人の特権ということでご容赦くださいませ。

宮原さんの発表で特に気になったポイントは、勉強会中に他の人のTweetのRTも含めてつぶやいていますが、以下のようなところです。「ベンチマークは科学!」って辺りは熱いですねw*2






ベンチマークに当たっての基礎的な考え方については、自分でもHPC勉強会*3で10分程度発表したことがありまして、宮原さんの発表はその問題意識にがっちりハマって、実践的なヒントをたくさんもらうことができました。ちなみに、当時の自分の発表資料は以下になります。


コンピュータシステムの特性や性能を正確に把握するというのは、非常に基本的なことではありますが、実際にやるためには対象への理解とその理解に即した測定を行うスキルの両方が必要で、かつ、技術面以外でもいろいろなバイアスがかかりやすい非常に難しいことだと思います。それを乗り越えて誰もが納得できる客観的な結果を出そうとするという姿勢が「科学」ということでしょう。

今回の勉強会は基礎編ともある通り、基本的な考え方や代表的な手法の紹介の内容だったので、次のベンチマーク勉強会では実践編として何かのベンチマークのハンズオンをやりたいという話が上がっています。ベンチマーク対象に取り上げるものがまだ決まっていませんが、自分としても開催に協力して実現したいと思っていますので、興味がある方は是非!

今日はこんなところで。

*1:ちなみに前回は「NANDフラッシュ祭り」で報告ブログはこちら→ http://sechiro.hatenablog.com/entry/2013/04/14/hbstudy_43_%E3%81%A7%E8%81%9E%E3%81%84%E3%81%9FioDrive_SDK_%E3%81%AE%E3%81%93%E3%81%A8%E3%80%82

*2:笑顔の宮原さんも素敵ですw

*3:ちなみに、この勉強会を発端にベンチマーク勉強会が始まっています。