whileループから放出されたすべての行をシェルの単一変数にどのように格納できますか?

whileループから放出されたすべての行をシェルの単一変数にどのように格納できますか?

私が知る限り、シェルのwhileループはサブシェルで実行されるので、ループの外側の変数を変更することはできません。

シェルスクリプトを作成していますが、マシンのすべての内部IPを変数に保存したいので、forループを使用して変数を処理し、iptablesを使用して1つずつフィルタリングします。

次のコードを書くことができます。

ip route show default | awk '{ print $5 }' | while read line; do
  ip address show dev ${line} scope global | awk '/inet / {sub(/\/.*/, "", $2); print $2}' | while read line; do
    echo "${line} "
  done
done

出力:

10.17.0.49 
192.168.1.4

私の質問は次のとおりです

whileループから放出されたこれらすべての行を単一の変数にどのように格納できますか(whileループ変数は揮発性なので)。

答え1

基本パスに含まれるインターフェイスのすべてのグローバルスコープローカルアドレスを印刷するために、より安定した方法でプログラム的に処理できるJSON形式を使用します。

perl -MJSON -le '
  $default_routes = decode_json(qx(ip -j route show default));
  for (@$default_routes) {$devs{$_->{dev}} = 1}
  $addresses = decode_json(qx(ip -j address show));
  for (@$addresses) {
    if ($devs{$_->{ifname}}) {
      for (@{$_->{addr_info}}) {
        print $_->{local} if $_->{scope} eq "global";
      }
    }
  }'

または同じものを使用してくださいjq

ip -j address show |
  jq -r --argjson devs "$(
      ip -j route show default|jq 'map({"key":.dev})|from_entries'
    )" '.[]|select(.ifname|in($devs)).addr_info[]|
      select(.scope == "global").local'

(JSON出力をサポートするには比較的新しいバージョンが必要ですiproute2)。

この項目(またはより一般的にはコマンドの各出力行)を配列に入れるには、次のようにbashします。

readarray -t array < <(
  that-command above
)

目標がデフォルトルートを介して送信されたパケットが取得できる送信元IPアドレスを取得することである場合は、例を参照してください。私の答え到着私のIPアドレスをどのように取得し、それをシェルスクリプトの変数に保存しますか?

答え2

実際の質問に簡潔に答えるには、とにかくwhileループの出力コンテキストを保存します。

出力をファイルに保存します/path/to/file。たとえば、次のようになります。

while command; do
    thing
done > /path/to/file

出力を変数に保存しますmy_var。たとえば、次のようになります。

my_var="$(while command; do thing; done)"

答え3

私はこれを行う2つの方法を知っています(バッシュから):

  1. プロセス置換と呼ばれるものを使用してください< <(command)(これはコンテンツをループにパイプしませんwhile)。
  2. 呼び出されたコマンドを使用してグループ化します{ code or commands }

したがって、すべてのIPを変数(またはこの場合は配列)に保存するには、次のコードを使用できます。

プロセスの代替:

process_subs () {
   local array=()
   while read -r line; do
     while read -r line; do
       array+=("$line")
     done < <(ip address show dev "${line}" scope global | awk '/inet / {sub(/\/.*/, "", $2); print $2}')
   done < <(ip route show default | awk '{ print $5 }')

   echo Array: "${array[@]}"
   echo Length: ${#array[@]}
}

コマンドのグループ化:

command_grouping () {

ip route show default | awk '{ print $5 }' |  while read -r line; do
ip address show dev "${line}" scope global | awk '/inet / {sub(/\/.*/, "", $2); print $2}' | { 
         local array=()
            while read -r line; do
            array+=("$line")
         done

      echo Array: "${array[@]}"
      echo Length: ${#array[@]}
      }
      done 
}

関連情報