GNU seq(1) 用のポータブル POSIX シェルの代替品?

GNU seq(1) 用のポータブル POSIX シェルの代替品?

seq(1)私はこれがGNU以外の他のシステムではうまくいくとは思わないことがわかりました。seq(1)POSIX(bashではない)シェルで書くことができる簡単な再実装は何ですか?

編集:少なくとも、さまざまなBSD、Solaris、およびMac OS Xでこれを使用する予定です。

答え1

代わりawkbc:

seq() (first=$1 incr=$2 last=$3
  echo "for (i = $first; i <= $last; i+=$incr) i" | bc -l
)

1つの利点は、CPUデュアルのサイズ/解像度によって制限されないことです。

$ seq '(2^200)' '(2^100)' '(2^200+2^102)'
1606938044258990275541962092341162602522202993782792835301376
1606938044258990275541962092342430253122431223184289538506752
1606938044258990275541962092343697903722659452585786241712128
1606938044258990275541962092344965554322887681987282944917504
1606938044258990275541962092346233204923115911388779648122880

しかし、数字が大きすぎる場合は改行に注意してください。

$ seq '(2^500)' '(2^100)' '(2^500+2^101)'
32733906078961418700131896968275991522166420460430647894832913680961\
33796404674554883270092325904157150886684127560071009217256545885393\
053328527589376
32733906078961418700131896968275991522166420460430647894832913680961\
33796404674554883270092325904157150886684127560071010484907146113622\
454825230794752
32733906078961418700131896968275991522166420460430647894832913680961\
33796404674554883270092325904157150886684127560071011752557746341851\
856321934000128

答え2

公開グループによるとPOSIX awkのサポートBEGINだから、次のようにすることができますawk

awk -v MYEND=6 'BEGIN { for(i=1;i<=MYEND;i++) print i }'

これは-v MYEND=6最初のパラメータの割り当てを表しますseq。つまり、次のように動作します。

seq() {
    end=$1
    awk -v end=$end 'BEGIN { for( i = 1; i <= end; i++) print i }'
}

あるいは、3つの変数、start、increment、およびendを使用することもできます。 (これは負の増加や浮動小数点をサポートしません):

seq() { 
    if [ "$#" = 1 ]; then
        start=1 incr=1 end=$1
    elif [ "$#" = 2 ]; then
        start=$1 incr=1 end=$2
    elif [ "$#" = 3 ]; then
        start=$1 incr=$2 end=$3
    else 
        echo "error: invalid number of arguments" >&2
        return 1
    fi
    if ! [ "$incr" -ge 1 ]; then
        echo "error: invalid increment (must be >= 1)" >&2
        return 1
    fi
    awk -v start=$start -v incr=$incr -v end=$end '
        BEGIN {  for( i = start; i <= end; i += incr) print i }'
}

追加ソラリス注:Solarisでは、/usr/bin/awk次のようになります。いいえPOSIXと互換性がある場合は、Solarisでnawkまたはを使用する必要があります/usr/xpg4/bin/awk

/usr/xpg4/binSolaris で POSIX 互換スクリプトを実行する場合は、PATH を最初に設定する必要があるかもしれません。

注:

答え3

whilePOSIXです

i=1
while [ "$i" -ne 11 ]
do    
    echo $i
    i=$(( $i + 1 ))
done

whileポータブルで汎用性があり、利用率が低いことが多いです。

答え4

私が考えることができる最も短く(デフォルトの目標)、最も安価な(消費されたシステムリソースに関して - 補助的な目標)バリエーションは次のとおりです。

while :; do echo x; done | sed 10q

「10」を希望の繰り返し回数に置き換えます。

次のように「for」ループで使用できます。

for i in `while :; do echo x; done | sed 10q`; do echo hello; done

ただし、「while」ループではより効率的に使用できます。

while :; do echo x; done | sed 10q | while read x; do echo hello; done

これにより、単一のプロセス呼び出しと潜在的に多数の「x」文字を「for」引数として一時的に保存することを防ぐことができます。

私が考える最も効率的な方法は

i=10; while case $i in 0) break; esac; do i=$(($i - 1)); echo hello; done

"echo"以外のシェル組み込み機能のみを使用し、他のプロセス呼び出しは必要ありません。残念ながら、台本で見るのはかなり醜くて不快です。ただし、スクリプトのパフォーマンスが重要な場合は、これが私が考えることができる最高の移植可能なソリューションです。

もちろん、awkとbcも対応することができます。しかし、どちらも作業に必要なユーティリティよりもはるかに強力なユーティリティなので、これらの簡単な作業に使用することは私にとってシステムリソースの無駄のようです。

関連情報