LoginSignup
26
14

More than 1 year has passed since last update.

シェルスクリプトの[ -lt, -le, -gt, -ge, -eq, -ne ]が嫌いな人に送るvalハック

Last updated at Posted at 2021-08-04

はじめに

シェルスクリプトでは数値を比較する時の演算子に -lt, -le, -gt, -ge, -eq, -ne を使います。これは他の言語で一般的な <<=>>===!= ではないため、分かりづらいという人がいるようです。-lt-gt は CSS の実体参照 &lt;&gt; と同じだし、英語の less than、greater than の略だし -le-ge は equal との組み合わせなので(英語が得意なのではなく LT はリトルの L が左側、GT はグレートの G が左側にあるという変な覚え方をしてるだけですがなにか?)、個人的には言語による文法の違い程度にしか思わずさほど気にならないのですが、記号よりは分かりづらいと言えば分かりづらいでしょう。

さてそんな人のために、この記事では [ ] とこれらの演算子をなくす val ハックというものを紹介します。ちなみに名前自体は私がつけたのでググっても見つかりません。

val ハック

少し複雑な計算式が含まれる条件式を例にします。

( (x + y)/(a * b) ) < (foo * bar)

まずこれをシェルスクリプトの一般的な書き方で書くと以下のようになります。

while [ $(( (x + y)/(a * b) )) -lt $((foo * bar)) ]
do
    # some calculations
done

シェルスクリプト特有の [ ]-lt が登場し元の条件式とは違って見えますね?

もしくは、次のように書くこともできます。元の条件式に少し近くなりましたが、[ ] は依然登場していますし、-lt が消えた代わりに意味的にも分かりづらい -ne 0 が必要になりました。

while [ $(( ( (x + y)/(a * b) ) < (foo * bar) )) -ne 0 ]
do
    # some calculations
done

これを val ハックを使って書くと以下のようになります。

while val $(( ( (x + y)/(a * b) ) < (foo * bar) ))
do
    # some calculations
done

[ ]-lt も消えてしまい、だいぶ元の条件式に近い形になりました。他の言語と同じように ==!= で比較することもできます。val というのは実際には以下の簡単な関数です。この関数にも [ ]-ne などの演算子が登場していません。実はシェルスクリプト特有の数値の比較演算子は一切不要なのです。これが val ハックです。

val() {
    return $((!$1))
}

変なことやってんなーって思いました?はい、私もです。名前は関数名を元に私がつけましたが、実はこのコードは POSIX に載っているものなのです。元のコードには必要のない $ が使用されていたためそこだけ取り除いています。

もっとも POSIX ではこの書き方を推奨しているわけではなく、算術式評価((( ))) ではなく算術式展開($(( )))を採用した理由として「([ ] でも十分対応できるし)複雑な条件式であってもこのような関数で読みやすく書くことができる」という文脈で使われています。

ちなみに算術式評価を使うとこのようになります(もちろん POSIX 準拠ではありません)。

while (( ( (x + y)/(a * b) ) < (foo * bar) ))
do
    # some calculations
done

確かに読みやすいけれども val $ が消えただけとも言えます。

さいごに

この方法を使うかどうかは皆さんにおまかせします。私はたぶん使いません。

26
14
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
14