루프 스루 변수


16

약 20 개의 다른 서버에서 rsync 및 업데이트 파일을 사용하는 bash 스크립트를 작성 중입니다.

rsync 부분을 알아 냈습니다. 내가 겪고있는 것은 변수 목록을 살펴 보는 것입니다.

내 스크립트는 지금까지 다음과 같습니다.

#!/bin/bash
SERVER1="192.xxx.xxx.2"
SERVER2="192.xxx.xxx.3"
SERVER3="192.xxx.xxx.4"
SERVER4="192.xxx.xxx.5"
SERVER5="192.xxx.xxx.6"
SERVER6="192.xxx.xxx.7"

for ((i=1; i<7; i++))
do
    echo [Server IP Address]
done

[Server IP Address]연관된 변수의 값은 어디에 있어야합니다. 따라서 i = 1 일 때 $ SERVER1의 값을 에코해야합니다.

나는 이것을 포함하여 몇 가지 반복을 시도했다.

echo "$SERVER$i"    # printed the value of i
echo "SERVER$i"     # printer "SERVER" plus the value of i ex: SERVER 1 where i = 1
echo $("SERVER$i")  # produced an error SERVER1: command not found where i = 1
echo $$SERVER$i     # printed a four digit number followed by "SERVER" plus the value of i
echo \$$SERVER$i    # printed "$" plus the value of i

스크립팅 한 지 오래되어서 뭔가 빠진 것을 알고 있습니다. 또한 지난 11 년 동안 사용한 C #을 사용하여 할 수있는 작업을 혼합하고 있다고 확신합니다.

내가 가능한 일을하려고합니까? 아니면이 값을 배열에 넣고 배열을 반복해야합니까? 위치 이름뿐만 아니라 프로덕션 IP 주소에도 이와 동일한 사항이 필요합니다.

이것은 원격 서버의 파일을 동기화하는 데 사용할 코드 블록을 반복 할 필요가 없도록하기위한 것입니다.


모든 답변과 의견에 감사드립니다. 나는 아마도 배열 접근법을 취할 것입니다.
Paul Stoner

답변:


33

배열을 사용하십시오.

#! /bin/bash
servers=( 192.xxx.xxx.2 192.xxx.xxx.3
          192.xxx.xxx.4 192.xxx.xxx.5
          192.xxx.xxx.6 192.xxx.xxx.7
)

for server in "${servers[@]}" ; do
    echo "$server"
done

6
+1; 그리고 배열 요소 앞뒤에 임의의 공백을 넣을 수 있으므로 OP에서와 같이 원하는 경우 한 줄에 하나의 요소를 넣을 수 있습니다.
ruakh

@ruakh : 감사합니다. 수행 할 수있는 작업을 보여주기 위해 업데이트되었습니다.
choroba

28

다른 답변에서 지적했듯이 배열이 가장 편리한 방법입니다. 그러나 완전성을 위해 요구하는 것은 간접 확장 입니다. 다음과 같이 다시 작성하면 샘플은이 방법으로도 작동합니다.

#!/bin/bash
SERVER1="192.xxx.xxx.2"
SERVER2="192.xxx.xxx.3"
SERVER3="192.xxx.xxx.4"
SERVER4="192.xxx.xxx.5"
SERVER5="192.xxx.xxx.6"
SERVER6="192.xxx.xxx.7"

for ((i=1; i<7; i++))
do
    servervar="SERVER$i"
    echo "${!servervar}"
done

for루프 에 IP 주소 목록을 넣는 것만으로도 괜찮다면 일부 중괄호 확장을 사용하여 필요한 모든 것을 반복 할 수도 있습니다.

#!/bin/bash

for server in \
192.xxx.xxx.{2..7} \
192.yyy.yyy.{42..50} \
192.zzz.zzz.254
do
    echo "$server"
done

그러나 (괄호 확장 가능) 목록을 재사용 해야하는 경우 목록을 사용하여 배열을 초기화하는 것이 좋습니다.

#!/bin/bash

servers=(
192.xxx.xxx.{2..7} 
192.yyy.yyy.{42..50}
192.zzz.zzz.254 )

for server in "${servers[@]}"
do
    echo "$server"
done

14

아마도 배열 중 하나가 스스로 대답 할 것이지만 이름을 직접 반복하는 것이 가능하다는 것을 지적하고 싶습니다. 넌 할 수있어

for name in "${!SERVER*}"; do
    echo "${!name}"
done

또는 4.3 이상에서 다음을 사용할 수 있습니다 nameref.

declare -n name
for name in "${!SERVER*}"; do
    echo "$name"
done

<4.3 솔루션을위한 모자 팁 ilkkachu .


2
간접 확장 ( ${!var})은 이전 버전의 Bash에서도 작동합니다.foo1=aa; foo2=bbb; foox=cccc; for p in "${!foo@}"; do echo "$p = ${!p}"; done
ilkkachu

도움을 주셔서 감사합니다. 내 답변을 업데이트했습니다.
kojiro

6

배열을 사용해야한다고 말한 사람은 모두 정확하지만 학업 연습으로 숫자로 끝나는 별도의 변수 (SERVER1, SERVER2 등)로 배열하기로 결정한 경우이 방법을 사용하십시오 그것:

for ((i=1; i<7; i++))
do
    eval echo \"\$SERVER$i\"
done

eval안전하게 사용하기 어렵습니다. 그렇습니다.하지만 bash 간접 확장이 일반적으로 더 나은 방법입니다.
Peter Cordes

습관. bash에서도 쉘 스크립트 작성을 시작했을 때 간접 확장은 없었습니다. 제대로 탈출하는 방법을 이해한다면 "평가"는 완벽하게 안전합니다. 그럼에도 불구하고 간접 확장이 더 낫지 만 이전 방법은 여전히 ​​작동한다는 점에 동의합니다. 어쨌든이 경우에는 수행하지 않을 것입니다. 나는 배열을 사용할 것이다!
빔 데이비스

이 경우 큰 따옴표를 이스케이프하지 않았으므로 eval완료 후에 는 echo $SERVER1아닙니다 echo "$SERVER1". 예, 안전하게 사용하는 것이 가능하지만 안전하지 않은 방법으로 사용 하기쉽지 않습니다.
Peter Cordes

서버 이름은 공백을 포함하지 않으므로이 경우에는 중요하지 않지만 ... 맞습니다. 큰 따옴표는 이스케이프 처리해야합니다. 답변 수정!
빔 데이비스

따옴표를 완전히 제거하는 것 (무엇을 보호하고 있다는 잘못된 인상을 피하기 위해)은 다른 방법입니다. 그러나 이스케이프 처리도 더 일반적인 방법이므로 +1입니다.
Peter Cordes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.