Hatena::ブログ(Diary)

(ひ)メモ このページをアンテナに追加 RSSフィード

2014-10-22 (Wed)

bashでsplitを書いてみた

空白絡むとどうにも配列で返せなかったんで、裏変数(_split)経由で結果渡すようにしてるのがイマイチ。。。

#!/bin/bash

set -u
set -e
export LANG="C"

split() {
  sep=$1
  str=$2

  _split=()
  if [[ $str =~ $sep ]]; then
    while IFS= read -r e; do
      _split+=("$e")
    done < <(echo "${str//$sep/$'\n'}")
  fi

  # declare -p _split >&2
}

split ':' 'foo:bar:baz'
declare -p _split
echo ">${_split[0]}<"

split ':' 'f o o:b a r:baz'
declare -p _split
echo ">${_split[0]}<"

split ':' ':'
declare -p _split
echo ">${_split[0]}<"

exit

結果:

declare -a _split='([0]="foo" [1]="bar" [2]="baz")'
>foo<
declare -a _split='([0]="f o o" [1]="b a r" [2]="baz")'
>f o o<
declare -a _split='([0]="" [1]="")'
><

別解

PerlのDBD::mysqlをlibmysqlclient.aとstatic linkしたい話

static linkするにあたっての動機、諸注意(ハメがあるので必読)は @ さんの

を参照してください。

ここではDBD::mysqlをビルドする際のオプションのみ記します。

http://dev.mysql.com/downloads/mysql/ からダウンロードできるrpm

  • MySQL-client-5.6.21-1.el6.x86_64.rpm
  • MySQL-devel-5.6.21-1.el6.x86_64.rpm
  • MySQL-shared-5.6.21-1.el6.x86_64.rpm

の場合、

$ ldconfig -p | grep libmysqlclient
        libmysqlclient.so.18 (libc6,x86-64) => /usr/lib64/libmysqlclient.so.18
        libmysqlclient.so (libc6,x86-64) => /usr/lib64/libmysqlclient.so

$ rpm -ql MySQL-devel | grep libmysqlclient.a
/usr/lib64/mysql/libmysqlclient.a

$ mysql_config --libs
-L/usr/lib64 -lmysqlclient -lpthread -lm -lrt -ldl

こういう感じの構成になっているので、

  • /usr/lib64の代わりにlibmysqlclient.aがある/usr/lib64/mysqlにライブラリパスを通す
  • libstdc++もリンクする

するように、このように

$ mysql_config --libs | sed -e 's@-L/usr/lib64@-L/usr/lib64/mysql@' -e 's@$@ -lstdc++@'
-L/usr/lib64/mysql -lmysqlclient -lpthread -lm -lrt -ldl -lstdc++

します。


ソースを展開してMakefile.PLを使ってビルドする場合は、--libsにこれを指定すればよいです。

$ perl Makefile.PL --libs="$(mysql_config --libs | sed -e 's@-L/usr/lib64@-L/usr/lib64/mysql@' -e 's@$@ -lstdc++@')"
$ make

$ ldd blib/arch/auto/DBD/mysql/mysql.so
        linux-vdso.so.1 =>  (0x00007fff9a52a000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f3434572000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f34342ee000)
        librt.so.1 => /lib64/librt.so.1 (0x00007f34340e5000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f3433ee1000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f3433ccb000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f3433936000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3434d84000)
# ↑libmysqlclient.so を dynamic linkしていない

$ perl -Iblib/lib -Iblib/arch -MDBD::mysql -e 1
# ↑ちゃんとモジュールをロードできる

$ sudo make install

ちなみに -lstdc++ していない場合はこのようにモジュールのロードで失敗します。

$ perl -Iblib/lib -Iblib/arch -MDBD::mysql -e 1
Can't load 'blib/arch/auto/DBD/mysql/mysql.so' for module DBD::mysql: blib/arch/auto/DBD/mysql/mysql.so: undefined symbol: __cxa_pure_virtual at /usr/lib64/perl5/DynaLoader.pm line 200.
 at - line 0
Compilation failed in require.
BEGIN failed--compilation aborted.

cpanmでインストールする場合は、--configure-args="--libs=..." に指定すればよいです。

$ mylib=$(mysql_config --libs | sed -e 's@-L/usr/lib64@-L/usr/lib64/mysql@' -e 's@$@ -lstdc++@')
$ cpanm -n DBD::mysql --configure-args="--libs='${mylib}'"

Oracle謹製のrpmには先程書いた http://dev.mysql.com/downloads/mysql/ で配布しているものの他に、yumレポジトリで配布しているものもあります。

  • mysql-community-client-5.6.21-2.el6.x86_64.rpm
  • mysql-community-common-5.6.21-2.el6.x86_64.rpm
  • mysql-community-devel-5.6.21-2.el6.x86_64.rpm
  • mysql-community-libs-5.6.21-2.el6.x86_64.rpm

なぜか両者ではライブラリファイルの配置が異なっているので気をつけてください。

このように、

$ ldconfig -p | grep libmysqlclient
        libmysqlclient.so.18 (libc6,x86-64) => /usr/lib64/mysql/libmysqlclient.so.18
        libmysqlclient.so (libc6,x86-64) => /usr/lib64/mysql/libmysqlclient.so

$ rpm -ql mysql-community-devel |  grep libmysqlclient.a
/usr/lib64/mysql/libmysqlclient.a

$ mysql_config --libs
-L/usr/lib64/mysql -lmysqlclient -lpthread -lm -lrt -ldl

yumで配布しているrpmのはlibmysqlclient.soも.aも同じディレクトリ/usr/lib64/mysqlにあります。

このままではstatic linkできないので、*.aを別のディレクトリにコピーして、そこにライブラリパスを通してビルドしないといけません。

$ mkdir /tmp/oreno-lib
$ cp /usr/lib64/mysql/*.a /tmp/oreno-lib/

$ mysql_config --libs
-L/usr/lib64/mysql -lmysqlclient -lpthread -lm -lrt -ldl
$ mylib="-L/tmp/oreno-lib -lmysqlclient -lpthread -lm -lrt -ldl -lstdc++"

$ perl Makefile.PL --libs="${mylib}"
  OR
$ cpanm -n DBD::mysql --configure-args="--libs='${mylib}'"

2014-08-28 (Thu)

VirtualBoxのスナップショットを簡単に管理できるツールを書きました。GO言語で。

VagrantではSahara pluginを使うことで、VMの状態を以前の状態に巻き戻すことができます(sandobx mode)。

VMの中でいろいろいじっている際に変更前の状態に戻せるのはとても便利なのですが、Saharaでは戻せるチェックポイントをひとつしか作れません。

自分の場合、深遠なChefのレシピを書いている過程で、戻せるポイントを何個か置きたくなることがよくあります。


さて、VagrantのバックエンドとしてVirtualBoxを使っている人は多いかと思います。

バックエンドがVritualBoxの場合、SaharaのsandboxはVirtualBoxのsnapshotを使って実現されています。

VirtualBoxのsnapshotはひとつだけでなくいくつでも作ることができます。

CUIVirtualBoxの操作(snapshotを作ったり)をするには、vboxmanage コマンドを使えばできるのですが、VMの名前が長かったりしてちょっと使いづらいです。

そこでsnapshotに関連する操作を簡単に実行できるラッパーツールを作りました。

使い方

動作中のVMの一覧を得る
$ vboxss list
vm1                 vm1_default_1404895653615_55181
vm2                 vm2_default_1404967162355_44921

VMの正規名は右側のながーいやつですが、vboxssは左の短縮名でも受け付けます。多くの場合、短縮名はvagrant initしたディレクトリ名になると思います。

あるVMのsnapshotの一覧を得る
$ vboxss list vm1
List of the snapshots of vm1_default_1404895653615_55181
initial                           e718f597-22b4-4bef-adf6-239fff78215f
install-apps                      5337e220-0075-46a5-8aaa-901361f352df
before-apply-chef                 703071da-26c1-4504-8c81-4535de33c2f2

listの後にVM名を指定すると、そのVMのsnapshotの一覧が表示されます。VM名は短縮名でも長い正規名でもOKです。

snapshotをとる
$ vboxss take vm1 provisioned

takeの後に、VM名と、snapshotにつける名前を指定します。

snapshotを使ってVMをレストアする
$ vboxss restore vm1 before-apply-chef

vm1という名のVMの状態を、before-apply-chefという名のsnapshotの状態に戻します。

vboxss restoreを実行すると、一旦VMが停止される点に留意してください。(レストア後、自動でまた立ち上がります)

snapshotを消す
$ vboxss delete vm1 provisioned

落穂ひろい

Goをまともに書いたのはこれが初めてなので「こう書いたほうがイイヨ!!」とかあったら教えてください><


バイナリのビルドと配布は Wercker を使ってます。@ さんと @ さんのを参考にさせてもらいましたー&Werckerのboxは lestrrat/peco-build をそのまま使わせてもらってます!!

2014-07-28 (Mon)

シンボリックリンク絡みでtail -Fが追従しないケース

tail -Fしているfluent-agent-liteでハマったのでメモ。

存在しないファイルをtail -Fした後、その名前のシンボリックリンクを作った場合

$ rm -fr ~/oreno-tmp && cd ~/oreno-tmp

$ tail -F tailme &
tail: cannot open `tailme' for reading: No such file or directory

$ ln -s real-file tailme
tail: cannot watch `tailme': No such file or directory

$ date >  real-file
$ date >> real-file
$ date >> real-file
  # tail -Fから流れてこない

ちなみに、存在するファイルを指すシンボリックをtail -Fしてる場合、途中で指す実ファイルが存在しなくなっても、実ファイルができ次第、追従してくれます。

$ rm -fr ~/oreno-tmp && cd ~/oreno-tmp

$ touch real-file.yesterday
$ ln -s real-file.yesterday tailme
$ tail -F tailme &
tail: inotify cannot be used, reverting to polling

$ date >> real-file.yesterday
Mon Jul 28 21:20:59 JST 2014

$ ln -sf real-file.today tailme
tail: `tailme' has become inaccessible: No such file or directory

$ date >> real-file.today
tail: `tailme' has appeared;  following end of new file
Mon Jul 28 21:21:39 JST 2014

$ date >> real-file.today
Mon Jul 28 21:21:48 JST 2014

つまり、既に存在する日付入りファイル名の実ファイルを指すシンボリックリンクがある場合は、00:00に今日の日付の名前を持つ実ファイルにシンボリックリンクを切り替えたときに、今日の日付の名前の実ファイルはあってもなくてもよい。

が、ド新規で追加したログファイルとかで、実ファイルもシンボリックリンクもない場合はハマる。


実ファイルがシンボリックリンクに変わった場合

$ rm -fr ~/oreno-tmp && cd ~/oreno-tmp

$ date > tailme
$ tail -F tailme &
Mon Jul 28 21:07:06 JST 2014

$ date >> tailme
Mon Jul 28 21:07:54 JST 2014

$ ln -sf real-file tailme
tail: `tailme' has become inaccessible: No such file or directory
tail: cannot watch `tailme': No such file or directory
$ date >> real-file
$ date >> real-file
$ date >> real-file
  # tail -Fから流れてこない
2003 | 11 | 12 |
2004 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 05 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 12 |
2012 | 01 | 02 | 03 | 06 | 08 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 |