拡張 POSIX シェルスクリプト Advent Calendar 2013、16日目の記事です。
ネタ枯渇と締切の危機の中、@hirose31 さん からネタを提供していただきました。 ありがとうございます! ありがとうございます! ありがとうございます! ありがとうございます! ありがとうございます! ありがとうございます! ありがとうございます! (コピペ)
ネタは一応まだ残っているのですが、いかんせん書くのに時間がかかりそうなものばかり。
そこで今日は頂いたネタでお茶を濁したいと思います。
test
コマンドにはいくつか罠がありますが、
その一つの紹介です。
$var
が空文字列のとき [ -n $var ]
はどのように評価されるか?
https://twitter.com/hirose31/status/412528403787415552
@satoh_fumiyasu 小ネタ思いつきました。 testで-nじゃなくて-zを使うべき→V=””; [ -n $V ] && echo T || echo F がTになる理由。ってクォートしろ、[[使えって話でもあるんですけどw
シェル好きには堪らない釣り針ですね! こんなの簡単!!
[
コマンドの-n
オプションは文字列を引数に取り、 文字列の長さが 0 でなければ真となる。- シェルは
[ -n $V ]
を変数展開して[ -n ]
にする。 - シェルは
[
コマンドに引数-n
だけを指定して実行する。 [
コマンドは引数が足りないのでエラー報告する。
確認しましょう。
$ V=""; [ -n $V ] && echo T || echo F
T
あれ?! エラーにならないどころか、結果は真?! 俺の知らないシェル依存の何かがあるのか?
$ /bin/dash -c 'V=""; [ -n $V ] && echo T || echo F'
T
$ /bin/bash -c 'V=""; [ -n $V ] && echo T || echo F'
T
$ /bin/ksh -c 'V=""; [ -n $V ] && echo T || echo F'
T
$ /bin/mksh -c 'V=""; [ -n $V ] && echo T || echo F'
T
$ /bin/zsh -c 'V=""; [ -n $V ] && echo T || echo F'
T
$ V=""; /usr/bin/test -n $V && echo T || echo F
T
\(^o^)/ワカラン
【長考中】( ´・ω) (´・ω・) (・ω・`) (ω・` )【30秒経過】
\(^o^)/ワカタ
$ V=""; [ -z ] && echo T || echo F
T
$ V=""; [ -f ] && echo T || echo F
T
$ V=""; [ -o ] && echo T || echo F
T
$ V=""; [ -urrryyyy ] && echo T || echo F
T
$ V=""; [ -ほげ ] && echo T || echo F
T
わかりますか?
答はそう、[
は引数が一つしかないとき、最初の引数に依らず [ 文字列 ]
と評価するためです。[ 文字列 ]
は [ -n 文字列 ]
と等価です。
[ -n -n ]
であるため真になるということですね。
[[
はどうか?
昨日紹介したように [[ 〜 ]]
ではワード分割は発生しない
ため、[[ -n $V ]]
はそのまま「[[
コマンドに引数 -n
, $V
(の変数展開結果), ]]
を指定して実行」
となり、
「$V の長さが 0 でなければ真 (0 か未定義なら偽)」という期待通りの動作になります。
また、[[ -n ]]
のように -n
オプションの引数を指定しない場合は
bash: unexpected argument ']]' to conditional unary operator
のようにこれも期待通りエラーとなります。
また、
(@t_tetosuki
さんのご指摘により、誤りとわかったため削除)[[
コマンド [
とは違い、[[ 文字列 ]]
という構文はない(不正でエラーとなる)であり、
[[ -n 文字列 ]]
を使わなくてはならない仕様です。
(いくつかの OS の各種シェルのマニュアルを確認しましたが、
この仕様が明示されている記述は見つけられませんでした)
環境やシェル種別、バージョンの依存度は?
手元にある環境で調べてみたところ、以下の test
コマンドは
V=""; [ -n $V ]
がエラーになることを確認しました。
- Solaris 10 の
/bin/sh
,/usr/bin/test
test: argument expected
と出力され終了コード 2 を返す。
- AIX 6.1 の
/bin/sh
(/bin/ksh
とハードリンク),/bin/ksh
,/usr/bin/test
test: argument expected
と出力され終了コード 1 を返す。
エラーになるかエラーにならず真になるかは環境依存のようですね。
まとめ
不明確で非直感的な動き・仕様の [
, test
は使ってはいけません。
明確で直感的な動きをする [[
を使いましょう。
ところで、12月25日はクリスマスな上に、
OSS 界隈で地味に活躍されているふみやすさんの誕生日ですね!
っ http://www.amazon.co.jp/registry/wishlist/27M7TV8CEEF6G?sort=priority
逆に、あなたの書いた OSS や Blog や Advent Calendar が気に入ったら何か送りたく なってしまうかもしれないので、プロフィールや Web サイトに あなたの Amazon 欲しいものリストの URL を貼っておいてくださいね!
私が勤める OSSTech っていう某弊社で社員募集しているようです。 人材紹介会社を介さなければ、入社後に 20万円のボーナス! 「ふみやすっていう人に紹介された」と言ってもらえると私にもボーナス!! → https://www.osstech.co.jp/recruit/
よろしければ、これまで参加した/参加予定のほかの Advent Calendar もどうぞ。
- Ansible Advent Calendar 2023
- シェル芸 Advent Calendar 2023
- 闇の魔術に対する防衛術 Advent Calendar 2023
- Ansible Advent Calendar 2023
- Ansible Advent Calendar 2020
- DNS温泉 Advent Calendar 2019
- OSSTech Advent Calendar 2019
- Ansible Advent Calendar 2018
- OSSTech Advent Calendar 2018
- Debian/Ubuntu Advent Calendar 2017
- Linux Advent Calendar 2017
- Shell Script Advent Calendar 2017
- Shell Script Advent Calendar 2016
- OpenLDAP と仲間たち Advent Calendar 2015
- Postfix Advent Calendar 2014
- 拡張 POSIX シェルスクリプト Advent Calendar 2013