ダミーを利用して条件分岐を回避する(シェルスクリプト)

課題

ディレクトリ内に、その名前がイチ以上の整数であるファイルが複数あるとする。その中でもっと大きい整数の、次の整数を求めたい。どのようにすればよいか。 例えば、以下のようなディレクトリを思い浮かべてほしい。

$ ls sample
1  10 2  3  4  5  6  7  8  9

解決策

たいていの場合の解決策としては、ファイルを探索してソートして末尾の数字を取得すれば良い。例えば以下の要領だ。

$ find sample -type f |
> sed 's!^sample/!!'  |
> sort -k1,1n         |
> tail -n1            |
> awk '{print $1+1}'
11


そしてここからが本題であるが、「たいていの場合」でない場合は、上記のコードでは動作しない。さて、それはどのような状況だろうか。

そう、ディレクトリ内にファイルが何も存在しない場合だ。このとき上記のコードでは、findコマンドから何も出力されず、空で終了する。そもそも、そのようなときにどうするべきか仕様に依るかもしれないが、自然に考えたら1と出力してほしくないだろうか。

ディレクトリが空の状態で1と出力するためにはどのようにすればよいだろう。タイトルである程度ネタばらしはしている。「ディレクトリが空であるかどうか判別して、空だったら1を出力するコードを追加する」といった回りくどいことはしなくて良い。そのかわりにダミーを追加してみよう。追加するのはこれだ。

$ find sample -type f |
> sed 's!^sample/!!'  |
> { echo 0; cat; }    |   ⇐ ★
> sort -k1,1n         |
> tail -n1            |
> awk '{print $1+1}'
1

このコードによって、パイプライン後半には少なくともひとつのデータが流れることになるため、結果が必ず出力される。

このコードはディレクトリが空でない状況でも動作する。なぜなら、存在する可能性がある数値は、必ずイチ以上であり、tail によりゼロは切り捨てられてしまうからだ。これにより、面倒な条件分岐を用意することなく、「たいていの場合」でない場合でも対応することができた。

所感

軽い気持ちで書いた記事であるが、シェルスクリプトを使いこなすうえで実は非常に重要な考え方である。このように、特定の目的を実現するために、自ら「余計な」データを付加することは、シェルスクリプトにおいては往々にして存在する。他の事例についても思いついたら紹介したい。