forループを介して他の関数を呼び出す関数呼び出し

forループを介して他の関数を呼び出す関数呼び出し

ループを使用して関数を呼び出し、for戻り値を変数に保存します。コードを実行するとcommand not foundエラーが発生します。何が問題なの?

#!/bin/bash

check_1()
{
    x_$1=$(check_2 $1)
}
check_2()
{
    ans=$((3+$1))
    echo $ans
}
for((i=1; i<=2;i++))
do
  check_1 $i
  tmp=x_$i
  echo ${!tmp}
done

上記のスクリプトを実行すると、次のような結果が得られます。

sample.sh: line 5: x_1=4: command not found
sample.sh: line 5: x_2=5: command not found

答え1

この方法では変数名を定義することはできません。他の変数の値を使用して変数名を設定しようとしてもx_$1=foo機能しません。より良い方法は配列を使用することです。

#!/bin/bash

check_1()
{
    x[$1]=$(check_2 "$1")

}
check_2()
{
    ans=$((3+$1))
    echo "$ans"
}
for((i=1; i<=2;i++))
do
  check_1 "$i"
  echo "${x[$i]}"
done

上記の結果は次のとおりです。

$ sample.sh
4
5

答え2

Teddenが言ったようにしなければなりません。彼の答え、代わりにbashの連想配列を使用してください。

しかし、あなたが主張し、十分に新しいbashを持っている場合は、次のものを使用できます。名前参照(ところで、これはマニュアルページで検索できる魔法の言葉です。)

i=1
declare -n tmp="foo_$i" # this is the nameref line
tmp="fooval"            # actually sets $foo_1
echo "$foo_1"           # prints fooval

関数の内部にある場合は、関数ローカル変数をインポートするlocal -n代わりに使用してください。declare -n

答え3

数学だけを勉強しない場合は、私がお勧めしたいのは安全でポータブル私は非常に厳格なテストを必要としない方法を知っています。

var1=string1
export "$var1=string2"
echo "$var1"
echo "$string1"

出力

string1
string2

しかし、数学を実行しているので、問題はecho変数を定義し、同時に現在のシェルで評価する必要があるときに変数の値をサブシェルに入れることです。

i=0 ; until [ $((i=$i+1)) -ge 3 ]
do  echo "\$x_$i = $((x_$i=3+$i))"
done     
echo $x_1 $x_2

出力

$x_1 = 4
$x_2 = 5
4 5

それで、あなたがすることは数学だけです。シェル操作の興味深い点は、これを使用して、現在のシェルの変数をサブシェルなしで2回安全に評価できることです。

POSIXにはこんな言葉があります:

算術拡張は、算術式を評価し、その値を変更するメカニズムを提供します。算術拡張の形式は次のとおりです。

$((expression))

式は二重引用符で囲まれたように処理する必要がありますが、式内の二重引用符は特に処理されません。シェルは、パラメータ拡張、コマンド置換、および引用符の削除のために式内のすべてのトークンを拡張する必要があります。

おそらくもっと興味深いことに、次のように言います。

算術式の変数に対するすべての変更は、パラメータ拡張などの算術拡張後に適用する必要があります"${x=value}"

シェル変数にx有効な整数定数(オプションで先行プラスまたはマイナス記号を含む)を形成する値が含まれている場合、算術拡張合計は同じ値を返す"$((x))"必要があります。"$(($x))"

したがって、算術置換コンテキストで変数が定義されている場合、その定義は現在の環境で維持されます。良い:

echo $((x=1)); echo $x
1
1

しかし、他の部分を追加すると - 特にシェルはすべてのタグを拡張する必要があります。 そしてそれ"$((x))""$(($x))"同じ値を返す必要があります。。上記のループがどのように機能するかを確認できますuntil

だから:

$((x_ #just a string
     $i #integer value
        = #assignment operator
          3 + #addition
              $i )) #same integer value

シェルは、$i割り当て演算子の前の文字列である変数シェルトークンと、合計が割り当てられる整数値に対して実行される追加演算という2つのコンテキストで拡張する必要があることがわかりますx_$i

配列は便利かもしれませんが、1つの形式を除いて移植性がなく、実装による混乱があります。また - あなたが要求した質問に対する答えは次のとおりです。

これが、次の機能が機能する理由です。

defv() {
    [ -n "${1##*[!0-9]*}" ] && # verify $1 is numeric only
    v=x_$1 &&                  # redefine caller loop var
    : $((x_$1=5+$1))           # : do nothing but expand arg
}

for v in 1 2 3 4 5             # init array
do  defv $v                    # defv() $indirection
    echo "$v = $(($v))"        # \$x_$indirection = $x_$indirection
done

出力

x_1 = 6
x_2 = 7
x_3 = 8
x_4 = 9
x_5 = 10

あなたの機能:

check_1()
{
    check_2 x_$1 $1
}
check_2()
{
    : $(($1=3+$2))
}
for((i=1; i<=2;i++))
do
  check_1 $i
  tmp=x_$i
  echo ${!tmp}
done

出力

4
5

関連情報