web-dev-qa-db-ja.com

POSIXシェルスクリプトで算術ループを作成するにはどうすればよいですか?

forで算術bashループを作成する方法を知っています。

POSIXシェルスクリプトで同等のループを実行するにはどうすればよいですか?

同じ目標を達成するにはさまざまな方法があるため、独自の答えを追加して、それがどのように機能するかを少し詳しく説明してください。

このようなbashループの例を次に示します。

#!/bin/bash
for (( i=1; i != 10; i++ ))
do
    echo "$i"
done
12

Shellcheck.net wiki で有用な情報を見つけました、引用します:

  1. バッシュ:

    for ((init; test; next)); do foo; done
    
  2. POSIX:

    : "$((init))"
    while [ "$((test))" -ne 0 ]; do foo; : "$((next))"; done
    

ただし、i++はPOSIXではないため、たとえば、i += 1またはi = i + 1に変換する必要があることに注意してください。


したがって、上記の質問のスクリプトは、次のようなルールを使用してPOSIXごとに書き直すことができます。

#!/bin/sh
: "$((i=1))"
while [ "$((i != 0))" -ne 0 ]
do
    echo "$i"
    : "$((i = i + 1))"
done

ここでも、次のようにすると読みやすくなります。

#!/bin/sh
i=1
while [ "$i" -ne 10 ]
do
    echo "$i"
    i=$((i + 1))
done

initと同様に、定数値を割り当てているため、算術式を評価する必要はありません。 testi != 10は、[式に簡単に変換できます。また、nextでは、算術式内の変数割り当てではなく、シェル変数割り当てを使用して、:と引用符の必要性を取り除くことができます。


i++-> i = i + 1のほかに、POSIX以外のksh/bash固有の構成の変換が必要になる場合があります。

  • i=1, j=2,算術演算子はreallyPOSIX ではありません(ksh93を使用する一部のロケールでは、小数点と競合します)。 : "$(((i=1) + (j=2)))"のように、+のような別の演算子に置き換えることもできますが、i=1 j=2を使用した方が読みやすくなります。
  • a[0]=1:POSIXシェルには配列がありません
  • i = 2**20:POSIXシェル構文にパワー演算子がありません。 <<はサポートされていますが、2の累乗の場合、i = 1 << 20を使用できます。他の権限については、bcに頼ることができます:i=$(echo "3 ^ 20" | bc)
  • i = RANDOM % 3:POSIXではありません。 POSIXツールチェストで最も近いのはi=$(awk 'BEGIN{srand(); print int(Rand() * 3)}')です。
13

上記の違いに関する詳細な背景知識に感謝します。 shellcheck.netを使用するときに私のために働く置換のドロップは以下の通りでした。

[〜#〜] bash [〜#〜]

for i in {1..100}; do  
  ...  
done  

[〜#〜] posix [〜#〜]

i=0; while [ $i -le 100 ]; do  
  ...  
  i=$(( i + 1 ))  
done

seqはseq 1 10を使用するオプションでもあると指摘する人もいます。ループを作成しますが、これはosがseqを持っているかどうかに依存します。

2
Jimmy MG Lim