제어 구문 예제_01 변수가 포함된 IP 주소 목록 파일을 읽어서 ping 명령어로 확인하기

 
  • 출처 : 유닉스 리눅스 쉘스크립트 예제사전_한빛미디어

명령어: sed, ping
키워드: for문, 템플릿 파일, 치환, 변수
사용처: 템플릿 파일을 사용해서 네트워크 개통을 확인하고 싶을 때


실행예제

$ cat ping_target.lst <------------- 템플릿 파일
%ADDR_HEAD%.1
%ADDR_HEAD%.2
%ADDR_HEAD%.3
%ADDR_HEAD%.4

$ ./for_command.sh 192.168.2
[Success] ping -> 192.168.2.1
[Success] ping -> 192.168.2.2
[Failed] ping -> 192.168.2.3
[Success] ping -> 192.168.2.4

스크립트

#!/bin/sh

# 명령행 인수 확인
if [ -z "$1" ]; then  #------------------------------------- 1(if문)
  echo "세 번째 옥텟까지의 IP 주소를 인수로 지정하세요." >&2
  exit 1
fi

# 대상 IP를 외부 파일 ping_target.lst에서
# %ADDR_HEAD% 부분을 치환해서 순서대로 얻기
for ipaddr in $(sed "s/%ADDR_HEAD/$1/" ping_target.lst)  #-- 2
do
  # ping 명령어 실행. 출력 결과는 필요 없으므로 /dev/null로 리다이렉트
  ping -c 1 $ipaddr > /dev/null 2>&1

  # 종료 스테이터스로 성공, 실패 표시
  if [ $? -eq 0 ]; then  #---------------------------------- 3(if문)
    echo "[Success] ping -> $ipaddr"
  else
    echo "[Failed] ping -> $ipaddr"
  fi
done

   

해설

이 스크립트는 외부 파일 ping_target.lst에 있는 IP 주소 목록에 ping 명령어로 통신 연결을 확인합니다. 여기서 외부 파일은 다음처럼 %ADDR_HEAD% 부분을 실행할 때 치환하는 형식이라고 가정합니다. 예를 들어 첫 번째줄은 %ADDR_HEAD%를 192.168.2로 치환해서 192.168.2.1에 ping을 실행합니다.

  • 파일1 IP 주소 목록 파일(ping_target.lst)

    %ADDR_HEAD%.1
    %ADDR_HEAD%.2
    %ADDR_HEAD%.3
    %ADDR_HEAD%.4
    

테스트 케이스로 192.168.0.0/24, 192.168.1.0/24… 네트워크를 확인하는 예라고 가정해서 IP 주소 세 번째 옥텟(Octet)까지(192.168.2 등)를 명령행 인수로 지정합니다.

예제에서는 for문을 사용합니다. for문은 일반적으로 인수에 파일 목록 등을 지정해서 실행하는 경우가 많습니다. 예를 들어 다음은 셸 경로명 확장을 사용해서 현재 디렉터리의 .html 확장자 파일을 순서대로 처리합니다.

  • 파일2 확장자 html 파일에 어떤 처리를 하기

    for filename in *.html
    do
        ... (어떤 처리)
    done
    

하지만 for문 in 뒤에는 셸이 목록으로 판별 가능한 것이 있으면 뭐라도 괜찮습니다. 예를 들어 in 뒤에 명령어 실행 결과를 사용하기 위해 명령어 치환 $( )을 두면 셸은 줄바꿈이나 스페이스를 구분자로 해석하므로 실행 결과마다 순서대로 처리할 수 있습니다. 즉, 위에 있는 소스를 다시 풀어 쓰면 다음과 같습니다.

  • 파일3 풀어쓴 예
    for filename in $(ls *.html)
    do
      ... (어떤 처리)
    done
    

하지만 이 소스는 파일명에 공백 문자가 들어 있는 파일이면 제대로 동작하지 않습니다. 제대로 동작하려면 IFS에 줄바꿈만 지정해야 합니다.

이렇듯 명령어를 직접 for문 in 뒤에 작성하는 방법은 여러 곳에 응용 가능하니 기억해 두기 바랍니다.

그럼 예제를 순서대로 확인해 봅니다. 1은 템플릿 파일을 치환하기 위해 지정하는 명령행 인수를 확인합니다. 첫 번째 인수를 의미하는 위치 파라미터 $1을 test 명령어 -z 연산자로 빈 문자열이 아닌지 확인합니다. -z 연산자는 빈 문자열이면 참이 되므로 참일 때 “인수를 지정하세요.”라고 표시하고 종료합니다.

2는 for문을 대상으로 명령어 치환 $( )을 이용해서 sed 명령어 결과를 사용합니다. 여기서 sed 명령어 대상 파일 ping_target.lst에는 %ADDR_HEAD%라는 고정문자열이 있습니다. 이걸 템플릿 파일로 보고 %ADDR_HEAD%라는 문자열을 명령행 인수로 지정한 문자열 $1으로 치환해서 IP 주소를 조합하고 셸 변수 ipaddr에 순서대로 대입합니다.

3은 셸 변수 ipaddr로 지정한 IP 주소를 대상으로 ping 명령어를 실행합니다. 여기서 ping 명령어 출력 결과는 사용하지 않으므로 /dev/null에 리다이렉트합니다. 종료 스테이터스 $?로 성공과 실패를 판별해서 echo 명령어로 결과를 표시합니다4.

이렇게 하면 외부 템플릿 파일을 이용한 처리를 for문으로 실행할 수 있습니다. 변수를 포함한 템플릿 파일을 만들고 싶을 때 사용 가능한 방법입니다.