while 루프에서 방출된 모든 행을 셸의 단일 변수에 어떻게 저장할 수 있습니까?

while 루프에서 방출된 모든 행을 셸의 단일 변수에 어떻게 저장할 수 있습니까?

내가 아는 한, 쉘의 while 루프는 서브쉘에서 실행되므로 루프 외부의 변수를 수정할 수 없습니다.

쉘 스크립트를 작성 중인데 머신의 모든 내부 IP를 변수에 저장하고 싶기 때문에 for 루프를 사용하여 변수를 처리하고 iptables를 사용하여 하나씩 필터링합니다.

다음 코드를 작성할 수 있습니다.

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).

이 항목(또는 더 일반적으로 명령의 출력 각 줄)을 array 에 넣으려면 다음을 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

나는 이를 수행하는 두 가지 방법을 알고 있습니다(배쉬에서):

  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 
}

관련 정보