2014年5月8日木曜日

bash でシェル変数が定義されているかを判定する方法は?

bash でシェル変数が(nullかどうかではなくて)定義されているかを判定したいと思って、調べたのですが、エレガントな方法がみつかりませんでした。

最初は、
if [ "${VAR:-UNDEF}" = "UNDEF" ] ; then
    ...
fi
だろうかと思ったのですが、VAR="" の時も真となってしまうので、微妙に違いました。それと、実際には無いはずとしても VAR="UNDEF" だったら、意図しない状況になってしまうのが引っかかります。処理内容によってはセキュリティホールのタネにもなるのではないか。

書籍調査/ネット検索の末に、
if ! set | grep -m 1 -q ^VAR= ; then
    ... # VARが未定義の場合に行う処理を記述
fi
とするしかなさそうなのですが、もっとエレガントな方法は無いものでしょうかね。現在のマシンでは大した処理コストではないですが、目的に対しては仰仰しいと思いました。
bash にそういった機能(isset のような)があったらいいように思いますが、需要がほとんどないし不要ということだろうか。

2014-05-10追記
匿名様(コメント参照)から情報頂き、
if [ -z "${VAR+x}" ] ; then    # VARが定義済み(nullを含む)の場合 x が返るので、-z でテストすれば OK
    ... # VARが未定義の場合に行う処理を記述
fi
と書けると知りました。少々難しい(慣れの問題?)ですが、手短に書けて良いでね。

2014-05-17追記
RHEL7.0 RC を調べていて、[ -v VAR ] が追加されているのを見つけました。
[root@hoge ~]# cat /etc/redhat-release 
Red Hat Enterprise Linux Server release 7.0 (Maipo)
[root@hoge ~]# bash --version
GNU bash, バージョン 4.2.45(1)-release (x86_64-redhat-linux-gnu)
...
[root@hoge ~]# help test
...
    Other operators:
    
      -o OPTION      True if the shell option OPTION is enabled.
      -v VAR  True if the shell variable VAR is set
...
bash の CHANGES を確認してみると、バージョン 4.2 で追加されたようです。
------------------------------------------------------------------------------
This document details the changes between this version, bash-4.2-alpha,
and the previous version, bash-4.1-release.
...
3.  New Features in Bash
...
f.  test/[/[[ have a new -v variable unary operator, which returns success if
    `variable' has been set.
...
いちおう動作確認です。
[root@hoge ~]# VAR="set" ; [ -v VAR ] ; echo $?
0
[root@hoge ~]# unset VAR ; [ -v VAR ] ; echo $?
1
RHEL6/CentOS6 以下の bash では使えないので、当面は利用できないですが、メモまで。

2014年4月29日火曜日

RHEL7.0 RC で、最新の ZFS on Linux を試してみた

Red Hat Network 上に RHEL7.0 RC が公開されたので、早速 ZFS を試してみました。
以下、メモです。

まず、dkms が必要ですが、これは EPEL の RHEL6/CentOS6 向けリポジトリから、.src.rpm を取ってきて再ビルドしてインストールしました。
# rpmbuild --rebuild dkms-2.2.0.3-20.el6.src.rpm
# ls /root/rpmbuild/RPMS/noarch
dkms-2.2.0.3-20.el7.noarch.rpm
# rpm -ivh /root/rpmbuild/RPMS/noarch/dkms-2.2.0.3-20.el7.noarch.rpm
つぎに、ZFS をインストールします。もちろん、RHEL7/CentOS7 向けのリポジトリは、まだありませんので、GitHub から最新のソースを取り出してビルドしました。
手順は以下のような感じです。
# mkdir zfs_on_linux
# cd zfs_on_linux
# git clone https://github.com/zfsonlinux/spl.git
# git clone https://github.com/zfsonlinux/zfs.git

# cd spl
# autoreconf -i  ※configureを生成するため、この操作が必要
# ./configure --with-config=user
# make rpm-utils rpm-dkms

# cd ../zfs
# autoreconf -i
# ./configure --with-config=user
# make rpm-utils rpm-dkms

# cd ..
# ls -1 spl/*.rpm
spl/spl-0.6.2-33_g89aa970.el7.src.rpm
spl/spl-0.6.2-33_g89aa970.el7.x86_64.rpm
spl/spl-debuginfo-0.6.2-33_g89aa970.el7.x86_64.rpm
spl/spl-dkms-0.6.2-33_g89aa970.el7.noarch.rpm
spl/spl-dkms-0.6.2-33_g89aa970.el7.src.rpm
# ls -1 zfs/*.rpm
zfs/zfs-0.6.2-259_gde39ec1.el7.src.rpm
zfs/zfs-0.6.2-259_gde39ec1.el7.x86_64.rpm
zfs/zfs-debuginfo-0.6.2-259_gde39ec1.el7.x86_64.rpm
zfs/zfs-devel-0.6.2-259_gde39ec1.el7.x86_64.rpm
zfs/zfs-dkms-0.6.2-259_gde39ec1.el7.noarch.rpm
zfs/zfs-dkms-0.6.2-259_gde39ec1.el7.src.rpm
zfs/zfs-dracut-0.6.2-259_gde39ec1.el7.x86_64.rpm
zfs/zfs-test-0.6.2-259_gde39ec1.el7.x86_64.rpm

# yum localinstall spl/spl-0.6.2-33_g89aa970.el7.x86_64.rpm \
spl/spl-dkms-0.6.2-33_g89aa970.el7.noarch.rpm \
zfs/zfs-0.6.2-259_gde39ec1.el7.x86_64.rpm \
zfs/zfs-dkms-0.6.2-259_gde39ec1.el7.noarch.rpm \
zfs/zfs-dracut-0.6.2-259_gde39ec1.el7.x86_64.rpm \
zfs/zfs-test-0.6.2-259_gde39ec1.el7.x86_64.rpm 
で、試運転結果です。
# uname -a
Linux hoge 3.10.0-121.el7.x86_64 #1 SMP Tue Apr 8 10:48:19 EDT 2014 x86_64 x86_64 x86_64 GNU/Linux
# zpool import tank4
# zpool list tank4
NAME    SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
tank4   368G   283G  84.5G    77%  1.00x  ONLINE  -
# zpool get all tank4
NAME   PROPERTY               VALUE                  SOURCE
tank4  size                   368G                   -
tank4  capacity               77%                    -
tank4  altroot                -                      default
tank4  health                 ONLINE                 -
tank4  guid                   1893700132493715388    default
tank4  version                -                      default
tank4  bootfs                 -                      default
tank4  delegation             on                     default
tank4  autoreplace            off                    default
tank4  cachefile              -                      default
tank4  failmode               wait                   default
tank4  listsnapshots          off                    default
tank4  autoexpand             off                    default
tank4  dedupditto             0                      default
tank4  dedupratio             1.00x                  -
tank4  free                   84.5G                  -
tank4  allocated              283G                   -
tank4  readonly               off                    -
tank4  ashift                 12                     local
tank4  comment                -                      default
tank4  expandsize             0                      -
tank4  freeing                0                      default
tank4  feature@async_destroy  enabled                local
tank4  feature@empty_bpobj    active                 local
tank4  feature@lz4_compress   active                 local
# zpool status tank4
  pool: tank4
 state: ONLINE
  scan: scrub repaired 12.1G in 1h34m with 0 errors on Sat Apr 26 12:37:25 2014
config:

 NAME                                                        STATE     READ WRITE CKSUM
 tank4                                                       ONLINE       0     0     0
   mirror-0                                                  ONLINE       0     0     0
     ata-HITACHI_HTS725050A9A364_xxxxxxxxxxxxxxxxxxxx-part1  ONLINE       0     0     0
     ata-HGST_HTS721010A9E630_yyyyyyyyyyyyyy-part1           ONLINE       0     0     0

errors: No known data errors
気になる性能は、どうかというと。
# uname -a
Linux hoge 3.10.0-121.el7.x86_64 #1 SMP Tue Apr 8 10:48:19 EDT 2014 x86_64 x86_64 x86_64 GNU/Linux
# zfs set compression=off tank4/backup
# cd /tank4/backup
# ls -l sda6.tar 
-rw-r--r-- 1 root root 10927441920 10月 20  2013 sda6.tar
# time tar xf sda6.tar 

real 3m23.413s
user 0m3.932s
sys 0m57.623s
# time rm -rf test.restore

real 0m9.153s
user 0m0.167s
sys 0m8.924s
にわかには信じ難いほど速くなってました!\(^0^)/
ピンと来ない方は、こちら を参照。同じマシン上に、RHEL7.0 RC のマルチブート環境を用意して、実験しています。
ちなみに、RHEL7 のデフォルトのファイルシステムは XFS ですが、マルチブートと相性が悪いのと、SSD 節約のため、Btrfs (compress-force=lzo) を使いました。Btrfs にインストールする手順は、こちら を参照。

2014-05-05追記
el7 向けの EPEL beta が既に公開されているので、dkms はそちらからインストールすれば済みます。

2014-06-17追記
別途用意した RHEL7 + ZOL 0.6.3 環境にて、SELinux をデフォルトの Enforcing にしたまま、tar の展開/削除を試したら、zfs_iput_taskq が大量に CPU 消費して、焦りました。
https://github.com/zfsonlinux/zfs/issues/1953 こちらの現象のようでした。RoadMap 上 0.6.5 で修正目標のようです。
もし、どうしても SELinux が必要なマシンで ZFS 使う方は、お気をつけて。

2014年3月22日土曜日

ZFS on Linux の vdev_id

ZFS on Linux が認識するデバイスパスは、デフォルトでは /dev/disk/by-id が使われます。次のような具合です。
[root@hoge ~]# uname -a
Linux hoge 2.6.32-431.5.1.el6.x86_64 #1 SMP Wed Feb 12 00:41:43 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
[root@hoge ~]# zpool status
  pool: tank4
 state: ONLINE
  scan: scrub repaired 0 in 1h18m with 0 errors on Sat Mar 15 20:39:47 2014
config:

 NAME                                                        STATE     READ WRITE CKSUM
 tank4                                                       ONLINE       0     0     0
   mirror-0                                                  ONLINE       0     0     0
     ata-HITACHI_HTS725050A9A364_xxxxxxxxxxxxxxxxxxxx-part1  ONLINE       0     0     0
     ata-HGST_HTS721010A9E630_yyyyyyyyyyyyyy-part1           ONLINE       0     0     0

errors: No known data errors
[root@hoge ~]# ls -l /dev/disk/by-id/ata-H*-part1
lrwxrwxrwx 1 root root 10 Mar 22 15:24 /dev/disk/by-id/ata-HGST_HTS721010A9E630_yyyyyyyyyyyyyy-part1 -> ../../sdb1
lrwxrwxrwx 1 root root 10 Mar 22 15:24 /dev/disk/by-id/ata-HITACHI_HTS725050A9A364_xxxxxxxxxxxxxxxxxxxx-part1 -> ../../sdc1
sdX なんかを使ってはよろしくない(ずれるから)のは分かりますが、どうにも長くて、特に同じ種類のディスクを使っていると個体を識別し難い(何番目のベイのディスクか不明瞭)と思っていました。
ZFS on Linux には、vdev_id というツールが用意されていて、この長いパスに別名(alias)を付与することができるようです。/etc/zfs/vdev_id.conf に次のように指定します。
#     by-vdev
#     name     fully qualified or base name of device link
alias  HITACHI_500G  ata-HITACHI_HTS725050A9A364_xxxxxxxxxxxxxxxxxxxx
alias  HGST___1000G  ata-HGST_HTS721010A9E630_yyyyyyyyyyyyyy
設定して再起動すると、/dev/disk/by-vdev というデバイスパスが生成されるようになります。
[root@hoge ~]# ls -l /dev/disk/by-vdev/H*-part1
lrwxrwxrwx 1 root root 10 Mar 22 15:24 /dev/disk/by-vdev/HGST___1000G-part1 -> ../../sdb1
lrwxrwxrwx 1 root root 10 Mar 22 15:24 /dev/disk/by-vdev/HITACHI_500G-part1 -> ../../sdc1
いったんプールを export してから、-d オプションを使って import し直せば、この便利な名前が使われるようになります。
[root@hoge ~]# zpool export tank4
[root@hoge ~]# zpool import -d /dev/disk/by-vdev tank4
[root@hoge ~]# zpool status tank4
  pool: tank4
 state: ONLINE
  scan: scrub repaired 0 in 1h18m with 0 errors on Sat Mar 15 20:39:47 2014
config:

 NAME                    STATE     READ WRITE CKSUM
 tank4                   ONLINE       0     0     0
   mirror-0              ONLINE       0     0     0
     HITACHI_500G-part1  ONLINE       0     0     0
     HGST___1000G-part1  ONLINE       0     0     0

errors: No known data errors
うまく名前を付与すれば物理的な接続(SATA portの何番に接続したディスクか?ベイの何段目のディスクか?等)も表現できて便利と思います。短めの名前をつければ、コンソール画面(横80桁)での操作時に、折り返し表示にならずに済むことにもなります。
人気ブログランキングへ にほんブログ村 IT技術ブログへ