ラベル Shell の投稿を表示しています。 すべての投稿を表示
ラベル Shell の投稿を表示しています。 すべての投稿を表示

2008-09-29

可搬なシェルスクリプト (2)

SUSv3は計算結果がnullか0でなければexprが0で終了すると規定している。

#! /bin/sh

set -e

output="-"

while getopts "ho:" opt; do
    case "$opt" in
        h)
            printf 'Usage: %s [ -h ] [ -o FILE ] [file...]\n' "$0"
            exit 1
            ;;
        o)
            output="$OPTARG"
            ;;
        ?)
            exit 1
            ;;
    esac
done

shift=`expr "$OPTIND" - "1"`
shift "$shift"

printf '[output=%s]\n' "$output"
printf '[%s]\n' "$@"

なにもオプションを指定しないと、シェルスクリプトは期待したように動作しない。shift=`expr "$OPTIND" - "1"`$OPTINDが1のときに0で終了する。set -eはコマンドが正常に終了しなかった場合にシェルスクリプトをただちに終了する。

shift=`expr "$OPTIND" - "1" || true`
shift "$shift"

2008-09-16

本物の配列

シェルスクリプトにおいてしばしば、$IFSevalを利用して疑似配列を扱う。疑似配列は疑似精液と同じくらい疑似なので、つまり疑似本番と同じくらい疑似である。だけど、本物の配列はかつてあり、ありつづけている。

#! /bin/sh

set -e

f() {
    if [ "$1" -eq "$2" ]; then
        return
    fi

    i="$1"
    s="$2"
    v="$3"
    shift 3

    printf '[%d:%s]\n' "$i" "$v"
    f `expr "$i" + 1` "$s" "$@" "$v"
}

f "0" "$#" "$@"

配列でなくリストというべきかもしれない(それとこれとどれほど違うだろう)。望むなら、execで末尾再帰、つまり、ほぼ無限が手に入る。そもそも、なんの役にたつのかと問う向きには応えよう。"$@"は本物の局所変数でもあるのだ。

2008-09-10

可搬なシェルスクリプト (1)

すべてのシステムがSUSv3に準拠しているわけはなく、すべてのシェルがSUSv3に準拠しているわけはなく、シェルスクリプトはシェルとユーティリティの混淆で、どちらが玉でどちらが石か判別できるわけはない。

Linux GNU/SystemsはBourne Again Shellを/bin/shに使うかもしれない(Ubutuはそうじゃない)。BSD系列は(Almquist Shellを含む)パブリックドメインのKorn Shellを使うかもしれない。Mac OS XはバージョンによってZ Shellを使ったりBoune Again Shellを使ったりする(ウンコ!)。SolarisはThe Heirloom Bounre Shellなる黙示的な名前をひりだした(ぶりぶりっ!)。

GNU Autoconfのマニュアルに曰く、

So while most modern systems do have a shell somewhere that meets the POSIX standard, the challenge is to find it.

The Heirloom Bourne Shellで動作すれば、現代的なシステムではだいたい動作するだろうと期待してもそれほど間違いではない。シェルの問題はユーティリティに押しつけられ、問題は面倒になるばかりだけれど。たとえば算術演算は$((expression))でなく`expr expression || true`と書かなければならない。