본문 바로가기

Learning/└◆Shell Scripts

[Shell Scripting] 본(Born) 쉘 프로그래밍_3

 

 

6

반복문

 

) --> 

) --> 

) --> 

) --> 

for 구문

while 구문

untile 구문

루프제어명령어

) --> 

루프 명령어는 명령어 혹은 명령어 집합을, 일정 횟수만큼 반복하거나 특정한 조건을 만족할 때 까지 계속 실행시켜야 하는 경우에 사용한다. 본 쉘에서는 for, while, until과 같은 세가지 루프를 제공하고 있다.

) --> 

) --> 

) --> 

for 구문  


for in do done

) --> 

지정된 범위안에서 루프를 돌리는데 사용되며 범위에 사용되는 것은 문자열 집합도 가능하다. for 루프 명령어는 정해진 횟수를 반복하는데 사용한다. for 명령어 다음에는 사용자 정의 변수가 나오고 이어서 키워드 in과 단어를 나열한다. 루프가 처음으로 실행될 때는 나열된 단어 목록 중 첫 번째 단어가 이 변수에 대입된다. 루프가 반복할 때마다 오른쪽으로 한 단어씩 이동하여 처리된다. 이 사용자 정의 변수에 단어가 대입되면 루프의 몸체에 해당하는 dodone 사이의 명령어들이 실행된다. 명령어 실행이 끝나면 다음 단어에 대해 루프의 몸체가 실행되고, 계속하여 나머지 단어들에 대해서도 이런한 과정을 반복한다.

) --> 

[표현식]

 

for VAR in VAR_LIST     <= 선언할때 $를 붙히지 않는 것 기억!

do

     statemnet

done

 

) --> 

) --> 

) --> 

[예제1] "for ~ in ~ do ~ done" 구문을 사용한 예제

) --> 

# vi for.sh

 

#!/bin/ksh

) --> 

for VAR in A B C D      <= A~D가 VAR에 한바퀴 들어가는 것

do

     echo $VAR

done

 

(Key Point) () for ~ in ~ do ~ done 구문

) --> 

# chmod 755 for.sh

# ./for.sh

 

A

B

C

D

 

) --> 

) --> 

[예제2] for 구문 간단한 예제

다음은 파일의 내용을 변수로 치환하여 다루는 방법의 예제이다.

) --> 

# vi cat_file.sh

 

#!/bin/ksh

) --> 

for NAME in `cat /etc/vsftpd/test.txt`

do

     echo "$NAME can't access to FTP SERVER"

done

 

(Key Point) () 파일의 내용을 변수로 변환하여 다루는 방법


cat ftpusers | grep -v '^#'| grep -v '^$' > test.txt <= 주석처리와 빈공간은 오류를 발생할 수 있으니 제거하겠다.

) --> 

# chmod 755 cat_file.sh

# ./cat_file.sh

) --> 

) --> 

) --> 

 

[참고] 파일 <-- 변환 --> 변수

(File -> Variable) 파일의 내용을 변수로 변환

for VAR in `cat file`

do

     echo "$VAR"

done

) --> 

(Variable -> File) 변수의 내용을 파일의 내용으로 변환

echo $VAR >> .tmp1

 

) --> 

) --> 

) --> 

[예제3] for 구문의 활용 예제

다른 스크립트에서 많이 사용될수 있는 부분을 쉘스크립트로 만들어서 명령어처럼 사용해 보자.

) --> 

새로운 명령어를 만들어 보자.

) --> 

# find / -name seq -type f

-> 명령어가 존재하지 않는다. 시스템 전체를 검색하게 되면 1~ 3분 정도 걸린다.

) --> 


seq명령어 => GNU계열에만 있어서 없으면 만들어주자

seq 1 3 => 1 2 3 으로 1부터 3까지 출력

seq 1 9 => 1 2 3 4 ... 7 8 9으로 1부터 9까지 출력


# cat seq

 

#!/bin/ksh

) --> 

if [ $# -ne 2 ] ; then

     echo "Usage : $0 Num1 Num2"       <=변수가 두개여서 처리하는 부분

     echo "Example: $0 1 10"

exit 1

fi

) --> 

SMALL=$1

BIG=$2

) --> 

while [ $SMALL -le $BIG ]

do

     echo "$SMALL"

     SMALL=`expr $SMALL + 1`

done

 

(Key Point) () 새로운 명령어를 만드는 방법



) --> 

# chmod 755 seq

) --> 

다음은 seq 명령어(새로 만들어진 명령어)를 다른 명령어에서 불러다가 쓰는 예이다.

) --> 

# seq_test.sh

 

#!/bin/ksh

) --> 

PATH=$PATH:/root/shell/study /* /root/shell/study/seq */

) --> 

for VAR in `seq 1 10`

do

echo "$VAR"

done

 

) --> 

# chmod 755 seq_test.sh

# ./seq_test.sh

 

1

2

3

4

5

6

7

8

9

10

 

) --> 

[예제 4] for 구문을 활용한 예제

) --> 

Data Stream 형태의 패키지를 한번에 설치 하는 스크립트를 만들어 보자.

) --> 

솔라리스의 패키지 형식

File System Format (EX: SUNWpkg/) => # pkgadd d . SUNWpkg

Data Stream Format (EX: top-3.6.1-sol10-x86-local) => # pkgadd d top-3.6.1-sol10-x86-local

) --> 

File System Format 패키지를 한번에 설치하기

# ls

 

SUNWpkg1 SUNWpkg2 SUNWpkg3 SUNWpkg4

 

) --> 

# pkgadd n d . all

) --> 

) --> 

Data Stream Format 패키지를 한번에 설치하기

-> 옵션을 지원하고 있지 않다.

) --> 

) --> 

# vi pkgall.sh

 

#!/bin/ksh

) --> 

#

# (1) Argument Error Check

#

if [ $# -ne 1 ] ; then

echo "-----------------------------------------------"

echo "$0 <Target Directory>"

echo "EX: $0 /test"

echo "-----------------------------------------------"

exit 1

fi

) --> 

#

# (2) Packages Installation

#

cd $1 && ls -1 $1 > /tmp/.tmp1 || exit 2

for PKG in `cat /tmp/.tmp1`

do

pkgadd -n -d $PKG <<- EOF

all

EOF

echo "$PKG installed : OK"

sleep 1

done

 

(Key Point) () for ~ in ~ do ~ done 구문() Here Documentation 사용법

) --> 

# chmod 755 pkgall.sh

) --> 

# mkdir -p /test1

# rcp 172.16.9.254:/root/packages/nmap/* /test1

# cd /test1

# gzip d *.gz

# cd -

) --> 

# ./pkgall.sh /test1

) --> 

) --> 

(다른 예제)

) --> 

# vi pkgall2.sh

 

#!/bin/ksh

) --> 

#

# (1) Directory Definition

#

if [ $# -gt 0 ] ; then

dir=$*

else

dir=.

fi

) --> 

#

# (2) Packages Installation

#

cd $dir && ls -1 $dir > /tmp/.tmp1 || exit 2

for PKG in `cat /tmp/.tmp1`

do

     pkgadd -n -d $PKG <<- EOF     <= <<-기호는 아래 EOF를 탭키만큼 띄어쓸 수 있는 명령어

     all

     EOF

     echo "$PKG installed : OK"

     sleep 1

done

 

(Key Point) () 디렉토리 처리 구문

) --> 

# chmod 755 pkgall.sh

) --> 

# mkdir -p /test1

# rcp 172.16.9.254:/root/packages/nmap/* /test1

# cd /test1

# gzip d *.gz

# cd -

) --> 

# ./pkgall.sh /test1





 

while 구문


while 조건 do done

) --> 

for 구문으로 어떤 명령을 지정한 횟수만큼 실행시키기가 어려울 경우에 사용한다. while 명령어는 바로 다음에 따라오는 명령어를 평가해서 종료 상태가 0이면 루프 몸체(dodone 사이)의 명령어들을 실행한다. 키워드 done에 다다르면, 프로그램의 제어는 다시 루프의 시작 부분으로 옮겨져서 명령어의 종료 상태를 다시 검사한다. while 루프에 의해 명령어의 종료 상태가 0이 아닌 값으로 바뀔때까지 루프가 계속된다. 종료 상태가 0이 아닌 값인 경우에는 프로그램의 제어는 doen 다음으로 옮겨져서 계속 실행된다.

) --> 

[표현식]

 

while condition

do

     statements

done

 

) --> 

) --> 

) --> 

[예제1] "while ~ do ~ done" 구문 사용 예

count 값을 증가 시켜 가면서 하나씩 출력하는 예제이다.

) --> 

# vi count.sh

 

#!/bin/ksh

) --> 

COUNT=1

while [ $COUNT -le 5 ]

do

     echo "Init Number: $COUNT"

     COUNT=`expr $COUNT + 1`

     echo "End Number: $COUNT"

     echo

done

 

) --> 

# chmod 755 count.sh

# ./count.sh

 

Init Number: 1

End Number : 2

) --> 

Init Number: 2

End Number : 3

) --> 

Init Number: 3

End Number : 4

) --> 

Init Number: 4

End Number : 5

) --> 

Init Number: 5

End Number : 6

) --> 

 

) --> 

) --> 

) --> 

[참고] while ~ do ~ done 구문의 활용

(웹 데몬의 개수를 모니터링)

# while [ 1 ]     <= 조건 1은 항상 참을 뜻한다 (=true)

> do

> ps -ef | grep httpd | wc -l | tee -a file.log

> sleep 3

> done


while :     <= 조건 :은 아무런 동작을 하지 않는다는 뜻으로 참과 같다

do

> ps -ef | grep httpd | wc -l | tee -a file.log

> sleep 3

done

) --> 

(telnet 서버에 접속한 원격호스트 수 모니터링)

# while true

> do

> netstat -an | grep EST | grep 172.16.8.XXX.23 | wc -l

> sleep 3

> done

[예제2] while 구문과 shift 사용 예

shift를 사용하여 프로그램 인자를 하나씩 주여 가면서 출력하는 예제이다.

) --> 

# vi shift.sh

 

#!/bin/ksh

) --> 

while [ $# -gt 0 ]

do

     echo "$# : $*"

     shift           <= default값 1이라서 숫자가 없으면 한칸 씩 왼쪽으로

done

 

$# : 위치 인자의 총 개수를 평가한다.

$* : 모든 위치 인자를 평가한다.

 

) --> 

# chmod 755 shift.sh

# ./shift.sh 1 2 3 4 5

 

5 : 1 2 3 4 5

4 : 2 3 4 5

3 : 3 4 5

2 : 4 5

1 : 5

 

) --> 

=> $* 표시중에서 awk $1을 변수에 넣고 동작시키고 shift시킨후 다시 awk1 $1로 처리하고 처리하고 반복하여

인자를 하나씩 줄여들여 옵션처리를 많이하고 있다. 전문적인 옵션처리 구문이 있는데도 불구하고 이런식으로 옵션처리를 한다.

) --> 

) --> 

) --> 

[예제3] 입력한 이름이 맞을때까지 계속 동작하는 예제이다.

) --> 

# cat quiz.sh

 

#!/bin/ksh

) --> 

echo "Who was the chief defense lawyer in the OJ case? : \c"

read ANSWER

) --> 

while [ $ANSWER != "Johnny" ]

do

echo "Wrong try again"

echo "Who was the chief defense lawyer in the OJ case? : \c"

read ANSWER

done

echo "You got it!"

 

) --> 

# chmod +x quiz.sh

# ./quiz.sh

 

Who was the chief defense lawyer in the OJ case? : John

Wrong try again

Who was the chief defense lawyer in the OJ case? : Johnny

You got it!

 

) --> 

) --> 



until 구문 => 잘 쓰이지 않는다.

) --> 

while 구문과 비슷하지만 condition이 거짓일 동안에만 실행이 된다. until 구문은 while 구문의 부정 형태이기 때문에 거의 사용되고 있지 않다.

) --> 

[표현식]

 

unitil condition

do

     statements

done

 

) --> 

) --> 

) --> 

[예제1]

) --> 

# cat until.sh

 

#!/bin/ksh

) --> 

until who | grep "$1" > /dev/null

do

echo "Until CMD doing ...."

sleep 5

done

) --> 

echo "Until CMD not doing ...."

 

) --> 

) --> 

 

7

루프 제어

 

) --> 

) --> 

) --> 

특별한 상황이 발생하면 루프를 탈출하거나 루프의 시작 부분으로 되돌아 가야 하는 경우가 있을 수 있다. 본 쉘에서는 이런한 특정 상황을 처리할 수 있는 루프 제어 명령어들을 제공한다.

) --> 

보통 루프(Loop)를 제어하는 명령어들은 break, continue 등이 존재한다. 반복문에서 continue 명령어는 반복문 수행 중간에 continue 이하 내용을 생략하고 다시 조건 검사를 하도록 한고, 반복문에서 break는 반복문을 강제적으로 빠져 나올때 사용한다.

) --> 

shift 명령어는 루프를 제어 하는 명령어는 아니지만 루프(반복문)문에서 많이 사용되는 명령어이기 때문에 이 장에서 다룬다.

) --> 

) --> 

) --> 

shift 명령어

) --> 

shift 명령어는 인자 목록의 순서상에서 지정한 횟수만큼 왼쪽으로 이동시킨다. 인자를 지정하지 않고 shift 명령어를 사용한 경우에는 인자 목록의 자리를 왼쪽으로 한번만 이동시킨다. 인자 목록이 일단 이동되고 나면 영구히 제거된다. , shift 명령어는 왼쪽에서 몇 번째 인자까지 제거할지 결정한다고도 볼수 있다. shift 명령어는 위치인자를 처리하기 위해 while 루프와 함께 많이 사용한다.

) --> 

) --> 

) --> 

) --> 

) --> 

[예제1] shift 명령어의 간단한 예

) --> 

# set 1 2 3 4 5

# shift

# echo $*

 

2 3 4 5

 

) --> 

# shift 3

# echo $*

 

5

 

) --> 

# shift 2

 

/bin/ksh: shift: bad number

 

) --> 

# echo $*

 

5

 

) --> 

) --> 

) --> 

) --> 

[예제2] shift 명령어를 이용한 인자을 줄여가며 출력하는 예이다.

) --> 

# cat doit.sh

 

#!/bin/ksh

) --> 

while [ $# -gt 0 ]

do

echo $*

shift

done

 

) --> 

# chmod +x doit.sh

# ./doit.sh 1 2 3 4 5

 

1 2 3 4 5

2 3 4 5

3 4 5

4 5

5

 

) --> 

break 명령어

) --> 

내장 명령어 break는 루프를 즉시 탈출하고자 하는 경우에 사용한다. break 명령어가 실행되면 프로그래의 제어는 곧바로 done 다음으로 이동된다. 여러 루프가 중첩되어 있을 때는 break를 사용한 루프에서만 빠져 나온다. 중첩 루프 구조에서 특정 루프를 빠져 나오고자 할 때는 break 명령어에 탈출 하고자 하는 외부 루프를 지정하기 위해 정수 인자를 사용할 수 있다. , 세 개의 루프가 중첩되어 있다면 가장 바깥쪽 루프 번호는 3번이 되고 중간 루프가 2, 그리고 맨 안쪽 루프가 1번이 된다. break는 무한 루프의 탈출에 유용하게 사용할 수 있다.

) --> 

# vi break_test.sh

 

while [조건1]

do

     statement1

     while [조건2]

     do

          statement2

          while [조건3]

          do

               statement3

               [조건4] && break N            /* N is number (EX: 1, 2, 3) */

               statement4

          done

     done

done

 

) --> 

(break 1 이면) "break 1" 이면 루프 하나 탈출

(break 2 이면) "break 2" 이면 루프 두개 탈출

(break 3 이면) "break 3" 이면 루프 세개 탈출

) --> 

단순하면서 복잡하게 만들기때문에 조심히 사용해야한다. 추천은 break 1 

Q로 나가거나 할때 많이 사용



) --> 

continue 명령어

) --> 

continue 명령어는 지정한 조건이 참이면 제어 루프의 시작으로 되돌린다. continue 아래의 명령어들은 모두 무시하게 된다. 중첩된 루프의 경우, continue 명령어는 가장 안쪽의 루프로 넘겨준다. 정수 인자를 사용하면 continue 명령어가 수행된 후 되돌아갈 루프를 지정해 줄 수 있다. 예를 들어 세 개의 루프가 중첩되어 있다면 가장 바깥쪽 루프 번호는 3번이 되고 중간 루프가 2, 그리고 맨 안쪽 루프가 1번이 된다.

) --> 

# cat continue_test.sh

 

while [조건1]

do

     statement1

     while [조건2]

     do

          statement2

          while [조건3]

          do

               statement3

               [조건4] && continue N          /* N is number (EX: 1, 2, 3) */

               statement4

          done

     done

done

 

) --> 

(continue 1 이면) "continue 1" 이면 [조건3]

(continue 2 이면) "continue 2" 이면 [조건2]

(continue 3 이면) "continue 3" 이면 [조건1]


회귀적으로 작업할때 continue많이 사용

) --> 

) --> 

) --> 

[예제1] yes 입력시 계속 입력 받기

다음 스크립트는 yes 라고 입력하면 계속 입력을 받고 다른 값을 입력하면 수행을 끝낸다.

) --> 

# cat cont_break.sh

 

#!/bin/ksh

) --> 

while :

do

     echo "Enter Your Choice(yes/other)?: \c"

     read X

     if [ $X = "yes" ] ; then

          continue

     else

          break

     fi

done

 

) --> 

(주의) break, continue는 잘 사용한다면 프로그램을 효율적으로 작성할 수 있지만, 프로그램을 복작하게 만들거나 해석하기 힘들도록 만들수도 있다. 주의하여 사용하여야 한다.

) --> 

# chmod 755 cont_break.sh

# ./cont_break.sh

 

Enter Your Choice(yes/other)?: yes

Enter Your Choice(yes/other)?: yes

Enter Your Choice(yes/other)?: yes

Enter Your Choice(yes/other)?: other

 

) --> 

) --> 

) --> 

[예제] continue를 사용하는 다른 예제

# vi script.sh

 

#!/bin/bash

) --> 

LOG=/var/log/messages

cp /var/log/messages /tmp/.tmp1

) --> 

while true

do

     sleep 30

     cp /var/log/messages /tmp/.tmp2

     cmp -s /tmp/.tmp1 /tmp/.tmp2 && continue     <=두개가 동일하면 continue동작 위로올려보낸다.

     mailx -s "[WARN] Mail Check" root < /tmp/.tmp2

     cp /var/log/messages /tmp/.tmp1

done

 

) --> 

# nohup /root/bin/script.sh & (# nohup CMD)

=> nohup붙히는 이유는 사용자가 로그아웃하면 실행했던 모든 터미널이 종료되서 nohup을 붙히면 사용자가 로그아웃해도 프로그램이 종료되지 않는데, 스크립트를 데몬모드로 동작시키려면 nohup 과 &를 붙혀야 24시간 데몬처럼 동작한다.



cmp 명령어 

# cmp file1 file2      <= 두 파일이 같으면 아무런 출력결과가 없다. 


# cmp file1 file3

 

file1 file3 differ: byte 11, line 3

1


# cmp -s file1 file3

 

# echo $?


diff 명령어

# diff file1 file2    <= 두 파일이 같으면 아무런 출력결과가 없다.


# diff file1 file3

3c3

< 3333

---

> 4444


# diff -c file1 file3        <=comments 옵션으로 전체를 다 보여준다.

*** file1       2015-11-09 11:29:48.000000000 +0900

--- file3       2015-11-09 11:30:18.000000000 +0900

***************

*** 1,3 ****

  1111

  2222

! 3333

--- 1,3 ----

  1111

  2222

 

! 4444


) --> 

) --> 

I/O 리다이렉션과 자식 쉘

) --> 

파이프나 리다이렉션을 이용하면 파일에서 루프로 입력을 전환할 수 있다. 같은 방법으로 출력 역시 루프에서 파일로 지정할 수 있다. 입출력 리다이렉션이나 파이프를 처리하기 위해서는 자식 쉘을 실행시켜야 한다. 루프 내에서 정의한 변수들은 스크립트의 나머지에서 참고 할 수 없다.

) --> 

) --> 

[예제1] I/O 리다이렉션을 통해 자식 쉘을 사용하는 경우의 예

) --> 

# vi numberit.sh

 

#!/bin/ksh

) --> 

if [ $# -ne 1 ] ; then

echo "Usage: $0 filename" >&2

exit 1

fi

) --> 

COUNT=1

cat $1 | while read LINE    <= 파이프 앞에 출력결과를 뒤에 입력결과로 들어가서 LINE에들어감

do

     [ $COUNT -eq 1 ] && echo "Processing file $1...." > /dev/tty

     echo $COUNT $LINE

     COUNT=`expr $COUNT + 1`

done > tmp$$                <= 반복구문만에 출력결과를 tmp$$에 저장

 

) --> 

# chmod 755 numberit.sh

# ./numberit.sh /etc/ftpd/ftpusers

 

Processing file /etc/ftpd/ftpusers

 

) --> 

# ls -l tmp*

 

-rw-r--r-- 1 root other 219 1111 03:29 tmp684

 

) --> 

# cat tmp684

 

..... (중략) .....

5 daemon

6 bin

7 sys

..... (중략) .....

 

) --> 

) --> 

) --> 

[예제2] I/O 리다이렉션을 통해 자식 쉘을 사용하는 경우의 예

) --> 

# vi input_output.sh

 

#!/bin/ksh

) --> 

while read LINE

do

echo $LINE

done < test.txt > output.txt

 

) -->test.txt에 내용이 LINE으로 들어가서 그 결과값을 output.txt에 저장하는 형태 


# chmod +x input_output.sh

# cat test.txt

 

John

Tom

Jain

Chan

 

) --> 

# ./input_output.sh

# cat output.txt

 

John

Tom

Jain

Chan

 

) --> 



정리


I/O Redirection

cat file1 | while read LINE                     <= read명령어 다음에 변수 여러개 쓸 수 있다. 변수를 각각 처리 가능하다

do                                                  추천

     statement

done > /tmp/tmp.$$

) --> 

while read LINE

do

     statment

done < /tmp/file1 > /tmp/tmp.$$

) --> 

for LINE in `cat file1`                         <= for와 in사이에 변수가 1개밖에 못온다.

do                                                  이름, 주민, 주소등이 하나로 들어가진다. (라인 단위로 다룰때 사용)

     statement

done > /tmp/tmp.$$

) --> 

) --> 

) --> 

 

8

시그널 트래핑

 

) --> 

) --> 

) --> 

프로그램을 수행 도중에 사용자가 Ctril+C Ctrl+키를 눌러 시그널이 방생하면 그 시그널이 도착하자마자 프로그램이 종료된다. 하지만 어떤 상황에서는 이런 시그널에 대해 바로 종료하면 곤란한 경우가 생길 수 있다. 사용자가 이런 시그널에 대해 적절한 동작을 지정해 줄수 있다. , 시그널을 무시해 버리거나, 필요한 몇몇 작업을 처리하고 종료하도록 설정하는 것이다. trap 명령어는 시그널에 대해 적절한 대처 방법을 설정 할 때 사용한다.

) --> 

시그널의 종류와 정의 부분은 "kill -l" 옵션으로, 또는 "# man -s 3head signal" 명령어를 통해 자세한 정보들을 볼수 있다.

) --> 

) --> 

시그널(signal)은 특정 키의 입력이나 예기치 못한 상황에서 한 프로세스가 다른 프로세스에게 보내거나 운영체제가 프로세스로 전송하는 일련의 숫자로 구성된 비동기 메시지라고 정의 한다.

) --> 

) --> 

[형식]

trap 'command ; command' signal_number

) --> 

) --> 

trap 명령의 사용범위는 다양하다.

시그널이 도착하면 특정한 동작을 하고 종료한다.

특정한 시그널이 오면 무시한다.

특정한 시그널이 오면 트랩 메시지를 출력한다.

) --> 

) --> 

trap 'rm tmp* ; exit 1' 1 2 15

위의 예는 1, 2, 15 시그널이 도착하면 모든 tmp 파일을 지우고 종료한다.

) --> 

trap " " 1 2

위의 예는 1 2 시그널이 오면 무시된다. trap 명령어 다음에 한쌍의 빈 따옴표가 오면 뒤에 나열한 시그널이 무시된다.

) --> 

trap 'echo "Control-C will not terminate $0."' 2

trap 'echo "Control-will not terminate $0."' 3

위의 예는 2 3 시그널이 오면 트랩 메세지를 출력하고 프로그램을 종료하지 않는다.

) --> 

시그널을 기본값으로 재설정하기 위해서는 trap 명령어 다음에 시그널 이름이나 번호만 지정한다. 다음예는 2 3 시그널을 기본값으로 재설정하는 예이다.

trap 2 3

[예제1] /etc/profile

sh 계열(sh, ksh, zsh, bash)을 사용하고 있는 사용자라면, 로그인 시에 /etc/profile 파일안의 내용이 실행된다. /etc/profile 읽혀지는 때에 시그널 트래핑에 의해 2, 3번 시그널은 동작하지 않는다.

) --> 

# cat /etc/profile

 

trap "" 2 3

export LOGNAME PATH

) --> 

if [ "$TERM" = "" ]

then

if /bin/i386

then

TERM=sun-color

else

TERM=sun

fi

export TERM

fi

) --> 

case "$0" in

-sh | -ksh | -jsh | -bash)

) --> 

if [ ! -f .hushlogin ]

then

/usr/sbin/quota

# Allow the user to break the Message-Of-The-Day only.

trap "trap '' 2" 2

/bin/cat -s /etc/motd

trap "" 2

) --> 

/bin/mail -E

case $? in

0)

echo "You have new mail." ;;

2)

echo "You have mail." ;;

esac

fi

esac

) --> 

umask 022

trap 2 3

 




 

) --> 

 

9

디버깅(Debugging)

 

) --> 

) --> 

) --> 

sh 명령어에 -n 옵션을 사용하면 스크립트를 수행해보지 않고 구문을 검사해 볼 수 있다.

구문 에러가 발생하면 에러의 내용을 출력해 준다. 스크립트에 아무런 에러가 없다면 아무것도 출력하지 않는다.

) --> 

스크립트 디버깅에 가장 자주 사용되는 방법은 set 명령에 -x 옵션을 사용하는 것이다. 또는 sh 명령에 -x 옵션을 사용하기도 한다. 이러한 옵션들을 사용하면 스크립트의 수행과정을 추적해 볼수 있다. 스크립트 안의 명령어들이 치환되는 과정을 먼저 출력하고 나서 명령어의 실행이 이루어진다. 스크립트 안의 문장을 보여 줄 때는 앞에 + 기호가 붙는다.

verbose 옵션이 커져 있거나, sh -v로 스크립트를 실행시키면, 각 행을 스크립트에 입력된 대로 출력하고 나서 실행 시킨다.

) --> 

 

명령어

옵션

기능

sh -x script

echo 옵션

(실행 추적하기) 스크립트의 각 행을 변수 치환하여 출력한 후 실행시킨다.

-x 옵션은 각 문장이 실행될 때 쉘이 이 문장들을 출력하게 된다. 구문은 쉘이 평가된 후에 출력되기 때문에 변수 치환, 와일드 카드 확장등의 결과를 알수 있다.

sh -v script

verbose 옵션

(조건부 실행) 스크립트의 각 행을 내용 그대로 출력한후 실행시킨다.

-v 옵션은 일반적으로 명령의 실행에 관련된 정보에 사용되기 때문에 매우 유용하다.

sh -n script

noexec 옵션

(구문 검사하기) 명령어를 실행시키지 않고 구문을 검사한다.

-n 옵션은 쉘 스크립트 구문을 싱행하지 않고 쉘 스크립트의 구조를 검사하는 방법을 제공한다.# sh -nv script.sh

 

) --> 

) --> 

디버깅 방법을 정리 하면 다음과 같다.

) --> 

첫 번째 디버깅 방법

# cat sample.sh

 

.....

set -x

.....          <= 사이에 있는 값이 자세하게 디버깅된다.

set +x

.....

 

) --> 

두 번째 디버깅 방법

# cat sample.sh

 

set -x          <= 끝까지 자세하게 출력

.....

 

) --> 

세 번째 디버깅 방법

# cat sample.sh

 

#!/bin/sh -x

or                                <= 코드를 고쳐야하는 경우가 생겨서 비추천

#!/bin/ksh -x

 

) --> 


이것은 꼭 기억해두자

네 번째 디버깅 방법

# sh -x script_file

# sh -xv script_file


=>

x - 어떻게 디버깅 되었는지 보여준다.

v - 원본 소스코드를 한번 더 보여준다.


bash -x ping.sh

+ START=200

+ END=202

+ NET=192.168.20

+ '[' 200 -le 202 ']'

+ ping -c 1 192.168.20.200

+ '[' 1 -eq 0 ']'

+ echo '192.168.20.200 : died'

192.168.20.200 : died

++ expr 200 + 1

+ START=201

+ '[' 201 -le 202 ']'

+ ping -c 1 192.168.20.201

+ '[' 1 -eq 0 ']'

+ echo '192.168.20.201 : died'

192.168.20.201 : died

++ expr 201 + 1

+ START=202

+ '[' 202 -le 202 ']'

+ ping -c 1 192.168.20.202

+ '[' 1 -eq 0 ']'

+ echo '192.168.20.202 : died'

192.168.20.202 : died

++ expr 202 + 1

+ START=203

+ '[' 203 -le 202 ']'




# bash -xv ping.sh 
#!/bin/bash

START=200
+ START=200
END=202
+ END=202
NET=192.168.20
+ NET=192.168.20

while [ $START -le $END ]
do
        ping -c 1 $NET.$START >/dev/null 2>&1
        if [ $? -eq 0 ] ; then
                echo "$NET.$START : alive"
        else
                echo "$NET.$START : died"
        fi
        START=`expr $START + 1`
done
+ '[' 200 -le 202 ']'
+ ping -c 1 192.168.20.200
+ '[' 1 -eq 0 ']'
+ echo '192.168.20.200 : died'
192.168.20.200 : died
expr $START + 1
++ expr 200 + 1
+ START=201
+ '[' 201 -le 202 ']'
+ ping -c 1 192.168.20.201
+ '[' 1 -eq 0 ']'
+ echo '192.168.20.201 : died'
192.168.20.201 : died
expr $START + 1
++ expr 201 + 1
+ START=202
+ '[' 202 -le 202 ']'
+ ping -c 1 192.168.20.202
+ '[' 1 -eq 0 ']'
+ echo '192.168.20.202 : died'
192.168.20.202 : died
expr $START + 1
++ expr 202 + 1
+ START=203
+ '[' 203 -le 202 ']'