各ループ反復でコマンド出力を別の変数に割り当てるにはどうすればよいですか?

各ループ反復でコマンド出力を別の変数に割り当てるにはどうすればよいですか?

次のスクリプトがあります。

for chain in http https ssh
do
 iptables -nvxL $chain | tail -1 | awk '{print $2}'
done

しかし、私が本当に望むのは、iptables各反復のコマンド出力を異なる変数としてキャプチャすることです。名前現在の値と同じでなければなりませんchain

したがって、最初のループ反復(ここでは)の場合は、$chain次のhttpようになりたいと思います。

http=$(iptables -nvxL http | tail -1 | awk '{print $2}')

次に私はこれが欲しい:

https=$(iptables -nvxL https | tail -1 | awk '{print $2}')

アイデアを得たことを願っていますが、どうすればいいかわかりません。

答え1

あなたの場合は、連想配列を使用します。

declare -A rules

for chain in http https ssh
do
   rules[$chain]=$(iptables -nvxL $chain | tail -1 | awk '{print $2}')
done

その後、次のように出力を逆参照して出力にアクセスできます。

printf -- "%s\n" "${rules['http']}"

または

for chain in http https ssh
do
    printf -- "%s\n" "${rules[$chain]}"
done

答え2

連想配列に対する答えは、ほぼ確実にあなたが望む方法です。

ただし、and(http、および$ referencesを使用)という変数が必要な場合は、名前を含む変数にコマンド出力を割り当てることができます。httpsssh$http$httpssshprintf -v$chain

for chain in http https ssh; do
    printf -v "$chain" '%s' "$(iptables -nvxL "$chain" | tail -1 | awk '{print $2}')"
done

によると、また参照してくださいこの回答、同じ目的を達成するために、typeset以下を使用できます。declare

for chain in http https ssh; do
    typeset "$chain"="$(iptables -nvxL "$chain" | tail -1 | awk '{print $2}')"
done

evalこの回答中に被害を受けた人は誰もいません。また、@penguin359の答えのように、ループから変数値を印刷するには、次のように使用できます。bash変数間接変数名の逆参照 - 繰り返しますが、evalsは必要ありません。

for chain in http https ssh; do
    echo ${!chain}
done

答え3

修正する:$2例に含まれている内容を引用するのを忘れました。これでOPは要求どおりに動作します。また、この回答のポイントと使用法は、eval複数の実装で標準のBourneシェル構文を使用して移植可能な例を提供することです。 bash、dash、zshで次のコードをすべてテストしました。 Dashは、Bourneシェル構文とより制限的で一貫性のある構文を使用するため、より良い移植性テストです。 Debian/Ubuntu のデフォルトシェルでもあります/bin/sh。 Dashには合計はありませんtypesetprintf -v私はそれが醜いと思いますevalが、Bourneシェルの最初のメカニズムであり、真の移植性を達成するための最良の方法です。

連想配列が良い方法だと思いますが、Bashに加えて他のBourneシェルに正確で移植可能な彼の元の質問に答えを提供したかったのです。動的変数名は、伝統的に次のように実行されます。

for chain in http https ssh; do
    eval $chain="\"\$(iptables -nvxL $chain | tail -1 | awk '{print \$2}')\""
done

Bourneシェルの演算子evalは、変数をコマンドに置き換えてから、完了するとコマンドで再実行(再評価)するために使用されます。コマンドを最初に置き換えた後、$chain変数と最初の参照セットが完了し、次のようになります。

http="$(iptables -nvxL http | tail -1 | awk '{print $2}')"

その後、これはコマンド拡張の変数割り当てとして評価されますiptables。内部コマンドは単一引用符を使用するため、ステートメントを引用するために使用できないため、評価にはおよびを使用し、eval結果"\"コマンド\""に必要に応じて二重引用符と一重引用符を渡します。コマンド拡張の周りに二重引用符は必要ないかもしれませんが、コマンドが複数の単語に拡張されると、いくつかのシェルの問題が発生します。これをダンプするには:

for chain in http https ssh; do
    eval echo \$$chain
done

最初のドル記号が引用されて渡されます。その結果、ループを解放した後、次の3つのコマンドが実行されます。

echo $http
echo $https
echo $ssh

関連情報