ユーザーが入力した回数だけループしようとすると、予期しない出力が表示されるのはなぜですか?

ユーザーが入力した回数だけループしようとすると、予期しない出力が表示されるのはなぜですか?

私は次の bash シェル スクリプトを書いています:

#!/bin/bash

declare -i N
read N
for i in {1..$N}
do
  echo "Number: $i"
done

(整数にdeclare -i Nなると思います)N

ただし、これを実行すると、次の出力が得られます。

>vim new.sh
>chmod +x passgen.sh
>./passgen.sh
15
Number: {1..15}

ここでは、ユーザーから制限を取得して、ループを実行します。

答え1

からman bash

展開の順序は、中括弧展開、チルダ展開、パラメータと変数の展開、算術展開、コマンド置換(左から右に実行)、単語分割、パス名展開です。

ご覧のとおり、中括弧の展開が最初なので、どうやら問題ではスキップされているようです。代わりに別のループを使用します。

答え2

ブレース拡張の問題はすでに指摘されていますが、私は次の点についてコメントします。

(declare -i N は N を整数にすると思います)

答えは「はい、そうです」です。これはコマンド インジェクションの脆弱性となるため問題です。整数属性が設定されている場合、変数に値が割り当てられるたびに、その値は算術式として解釈されます。

たとえば、ユーザーがa[$(reboot)]そのプロンプトで入力すると、再起動が試行されます。read

bashこれは、算術式が評価されるたびにzsh、および で発生する一般的な問題です。の有無にかかわらず、ksh93 スタイルの形式を使用した場合でも、 の内容がその算術コンテキストで評価されるため、問題になります。kshfor (( i = 1; i <= N; i++ ))declare -i NN

for i in {1..$N}declare -i Nksh、zsh、またはでは ( なし)で問題ありませんyash -o braceexpand(意味不明なループが発生しますが、コマンド インジェクションの脆弱性は発生しません)。また、実装が に基づいていないsh場合は、標準の構文を使用することもできます。shksh

#! /bin/sh -
IFS= read -r N
i=1; while [ "$i" -lt "$N" ]; do
  printf '%s\n' "Number: $n"
done

ksh[依然として のオペランドを-lt算術式として扱うため、コマンド インジェクションの脆弱性が依然として生じます。/ /内で[[ $i -lt $N ]]または を使用しないでください。これも問題を引き起こします。(( i < N ))bashzshksh

あるいは、awk/perlまたは適切なプログラミング言語を使用してループを実行することも、最初に入力をサニタイズすることもできます。

関連情報