UNIX 및실습 13 장. 배시쉘프로그래밍
학습목표 다양한쉘변수를이해하고활용하는방법을익힌다 사용자로부터입력을받아스크립트파일에서처리하는방법을익힌다 다양한연산자와문자열테스트, 파일테스트를활용하는방법을익힌다 조건문과반복문의사용방법을익힌다 함수를이용해스크립트를작성하는방법을익힌다 스크립트의실행오류를찾아수정하는방법을익힌다 2
01. 쉘스크립트 스크립트? 인터프리터라불리는다른프로그램에의해실행되는프로그램 자바스크립트, Perl, 파이썬, 쉘스크립트 쉘이실행하는프로그램 유닉스명령 + 쉘이제공하는프로그램구성요소 쉘스크립트파일이름은키워드나앨리어스, 내장명령과같은이름을쓰지않는것이바람직함 쉘명령실행순서 : 앨리어스 키워드 (if, while, until 등 ) 함수 내장명령 (cd, echo 등 ) 스크립트, 유틸리트등 PATH 경로에있는실행가능한파일 3
쉘스크립트만들기 vi 에디터로편집 예 : test_script #!/bin/bash # My First Script Program print I love UNIX! pwd 4
쉘스크립트실행하기 스크립트실행방법 쉘을실행하면서인자로스크립트이름지정 ssh lily.mmu.ac.kr $ bash test_script I love UNIX! /home/user1/unix/ch13 $ 파일을직접실행 ssh lily.mmu.ac.kr $ chmod +x test_script $./test_script I love UNIX! /home/user1/unix/ch13 $ PATH 환경변수에현재디렉토리 (.) 가포함되어있지않으면./ 를꼭지정해야함!! 5
쉘스크립트종료하기 - exit exit [ 종료상태 ] 스크립트의종료 종료상태를 $? 변수에저장 사용예 : test_exit 스크립트가종료되는경우? 파일의마지막명령을실행 exit 문실행 #!/bin/bash #test_exit : exit 과 $? 를테스트하는프로그램 exit 20 텔넷 cookook.co.kr $ test_exit $ echo $? 20 $ 6
스크립트파일의구성요소 - #! 매직넘버 파일의가장처음에위치 스크립트를실행할프로그램지정 각쉘마다제공하는스크립트언어의문법이조금씩다르므로, 이스크립트를실행할쉘을지정해주어야올바로실행됨 쉘이아닌, 다른실행가능한명령을지정해주어도됨 예 : test_sharp #!/bin/more # test_sharp: 스스로를출력하는스크립트 # 이스크립트를시행시키면자기자신을화면에출력합니다. # 주석문도모두출력되지요. echo This line is printed. 7
스크립트파일의구성요소 - # 주석 (comment) 프로그램에대한설명 행전체, 또는행의일부를주석으로처리할수있음 예 : test_sharp2 #!/bin/rm # test_sharp2 : 자기자신을지우는스크립트 # 이스크립트를실행시키면이파일이지워집니다. WHATEVER=65 print 이부분은절대로출력되지않을겁니다. exit $WHATEVER # exit 문도실행되지않지요. 8
스크립트파일의구성요소 - 쉘명령 쉘이실행할수있는모든명령어사용가능 여러명령을반복수행해야할때스크립트파일로저장하여실행 예 : find_script #!/bin/bash # find_script : /bin, /usr/bin 에있는쉘스크립트검색 cd /bin file * grep script cd /usr/bin file * grep script ssh lily.mmu.ac.kr $./find_script 2to3: aalib-config: adrgen: afmtodit: ( 중략 ) xslt-config: zipgrep: $ executable /usr/bin/python2.6 script executable shell script executable /bin/ksh script executable /usr/bin/perl script executable shell script executable shell script 9
스크립트파일의구성요소 - 쉘프로그램 각쉘이제공하는프로그램을위한구문 쉘변수, 인자처리, 각종연산자, 제어문등포함 시스템이사용하는스크립트의예 : $ more /etc/rc2.d/s47pppd #!/usr/sbin/sh # # Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. # 시스템이부팅될때실행되는스크립트 PATH=/sbin:/usr/bin:/usr/sbin; export PATH PPPDIR=/etc/ppp; export PPPDIR case "$1" in 'start') --More--(10%) 10
02. 쉘변수사용하기 변수 : 프로그램에서처리하는다양한정보를저장하는곳 종류 쉘변수 ( 현재쉘에서만사용가능 ), 환경변수 ( 모든쉘에서사용가능 ) 지정방법 변수명 = 값 쉘변수표현식 : 을사용하지않으면널값을갖고있어도변수가정의된것으로간주 형식 $name $(name) ${name:-word} ${name:=word} ${name:+word} ${name:?word} 의미 name의값으로대체 name의값으로대치. 변수이름이다른구문과인접해있을때사용 name이정의되어있으면그값을, 그렇지않으면 word값사용 name이정의되지않았았거나, 널이라면 word를대입하고그값사용 name이정의되어있고, 그값이널이아니면 word 값을사용 name이정의되어있고널문자가아니면그값을사용한다. 그렇지않으면 word 출력후종료 11
쉘변수사용하기 - 사용예 ssh lily.mmu.ac.kr $ test=cookbook $ echo $test cookbook $ echo ${test:-word} cookbook $ echo ${test1:-word} word $ echo ${test:=word} cookbook $ echo ${test1:=word} word $ echo ${test1:=word1} word $ echo ${test:+word} word $ echo ${test:?word} cookbook $ ^test^test2 echo ${test2:?word} -bash: test2: word $ 12 1) test 변수에 cookbook" 문자열저장 2) test 변수값출력 3) test 변수가정의되어있으므로해당값 출력 4) tset1 변수가없으므로문자열 word 출력 5) test 변수가정의되어있으므로해당값출력 6) test1 변수가없으므로 word 를그값으로저장 7) tset1 변수가 6) 에서저장되어있으므로그값출력 8) test 변수가정의되어있으므로 word 출력 9) test 변수가정의되어있으므로해당값출력 10) tset2 변수가없으므로 word 출력후스크립트종료
쉘변수문자열처리 변수의값이문자열일때문자열내패턴을찾아일부분을제거하는표현식 2.x 이전의배시쉘에서는동작하지않음 표현식 ${vairable%pattern} ${variable%%pattern} ${variable#pattern} ${variable##pattern} 기능 variable 의뒤부터패턴과일치하는첫번째부분을찾아서제거 variable 값의뒤부터패턴과일치하는가장큰부분을찾아서제거 variable 값의앞부터패턴과일치하는첫번째부분을찾아서제거 variable 값의앞부터패턴과일치하는가장큰부분을찾아서제거 13
쉘변수문자열처리 - %, # 사용예 % : 뒤에서부터패턴과일치하는최소부분을제거 (%% 는최대부분 ) ssh lily.mmu.ac.kr $ path1="/usr/bin/local/bin" $ echo ${path1%/bin} /usr/bin/local $ echo ${path1%%/bin*} /usr $ %% 사용시지정한패턴이변수값중간에있다면, 패턴이후에임의의값이나올수있다는표시로 * 지정해야함! # : 앞에서부터패턴과일치하는최소부분을제거 (## 은최대부분 ) ssh lily.mmu.ac.kr $ path2= /home/user1/.profile" $ echo ${path2#/home} /usr1/.profile $ echo ${path2##*/}.profile $ ## 을사용할때는패턴앞에 * 지정!! 이예는경로에서파일명만추출할때사용 14
쉘변수문자열처리 - # 변수 사용예 # 변수 : 변수에저장된문자의개수출력 ssh lily.mmu.ac.kr $ echo ${#path1} 18 $ echo ${#path2} 20 $ 15
명령행인자처리 명령행인자 스크립트를실행할때인자로주어진값 위치매개변수 명령행인자를저장하는스크립트변수 인자의위치에따라이름이정해짐 명령행인자 의미 $0 쉘스크립트의이름 $1 - $9 명령행에주어진첫번째부터 9번째까지인자 $(10) 10번째인자 $# 전체인자개수 $* 모든인자 $@ $* 과같은의미 $* $1 $2 $3 $@" $1 $2 $3 $? 최근실행된명령의종료값 16
명령행인자처리 사용예 #!/bin/bash # test_position: 명령행인자를테스트 # echo $* : $* echo '$# : ' $# echo '$@ : ' $@ echo $1 $2 $3 set -- ssh lily.mmu.ac.kr $ chmod +x test_position $./test_position one twon three $* : one two three $# : 3 $@ : one two three one two three $ 17
쉘특수문자및명령처리 인용부호 : 쉘특수문자의의미를없애기위해사용 인용부호기능사용법 작은따옴표 ( ) 모든특수문자들이해석되는것을막음 $echo $test $test 큰따옴표 ( ) 변수나명령의대체만허용 $echo $test 100 역슬래시 (\) 단일문자가해석되는것을막음 $echo \$test $test 명령대체 : 명령실행결과를문자열로변환 기호 백쿼터 (` `) 사용법 $ echo `date` Sunday, April 15, 2012 11:05:06 AM KST $( 명령 ) $ echo $(date) Sunday, April 15, 2012 11:15:11 AM KST 18
사용자로부터입력받기 - read 쉘내장명령으로터미널이나파일로부터입력처리 사용형식 형식 의미 read x read first last read -p prompt 표준입력에서한행을입력받아 x 에저장 표준입력에서한행을입력받아첫번째단어를 first 에저장하고나머지모두를 last 에저장 prompt 를출력하고입력을기다린다. 입력된값은 REPLY 변수에저장 19
사용자로부터입력받기 - read 사용예 : test_read #!/bin/bash # 키보드입력처리를테스트하는스크립트 read x echo x : $x # 아무메시지없이사용자입력을기다림 # 사용자가임의의값을입력하면출력 read x y echo x is $x y is $y # 첫단어는 x, 나머지는 y 에저장 # x, y 값출력 read -p Input : echo input : $REPLY # Input : 을출력한후입력기다림 # $REPLY 에자동저장된입력값출력 20
문서를통한입력 - here 문서 표준입력을사용자로부터직접받아들이지않고자동처리 TERMINATOR 가입력될때까지기술된부분을키보드입력으로처리 키보드입력의종료문자로사용하는 EOF(^D) 문자를파일안에서사용할수없기때문에입력종료를나타내는문자열을지정하여사용 예 : test_here 명령 << TERMINATOR 입력내용 TERMINATOR #!/bin/bash # here 문서테스트. user1 에게메일을보냄 mail user1 << END This is a test mail for here document END 21
04. 연산자 프로그램에서자료를처리하는방법 산술연산자, 비교연산자, 논리연산자, 비트연산자제공 수치연산자사용시 let 또는 (( )) 사용해야함 연산자의미사용예 - 음수 ( 단항연산 ) -5! 논리부정 (not) ((! x < y )) ~ 비트반전 (not) ~y * / % 곱셈, 나눗셈, 나머지연산 let y=3 * 5 + - 덧셈, 뺄셈 let x=x+1 << >> 비트왼쪽시프트, 비트오른쪽시프트 (( y = x << 3 )) <= >= < > ==!= 비교연산 (( x < y )) & ^ 비트 AND, XOR, OR 연산 let z = x ^ y && 논리 AND, OR (( x<y x==3 )) = 변수값지정 let z=1 *= /= %= += == <<= >>= &= ^= = 단축연산 let z+=1 22
사용예 ssh lily.mmu.ac.kr 연산자 $ a=5 $ echo $a 5 $ let a = 20 ----> let 에서공백을사용못함 -bash: let: =: syntax error: operand expected (error token is "=") $ let a = 20 ----> 공백을포함하려면 " " 사용해야함 $ print $a 20 $ (( a = 30 )) ----> (( )) 에서는공백사용가능 $ echo $a 30 $ a=$a*5 ----> let 이나 (( )) 을사용하지않으면문자열로처리 $ echo $a 30*5 $ echo $((5*6)) ----> 계산결과를바로출력할수있음 30 $ echo $((! 2 + 3 * 4 )) ----> 우선순위에따라! 먼저수행. 2 는 0 이됨. 12 $ echo $(( 2 << 1 )) ----> 왼쪽 shift 는 *2 와같음. 2 번 shift 는 *4 4 $ echo $(( 3 ^ 5 )) ----> XOR 연산결과 6 $ 23
05. 제어문 프로그램내의문장실행순서를제어하는것 선택적실행문 프로그램실행문을조건에따라선택적으로실행 if, select 반복실행문 프로그램실행문을정해진횟수나조건에따라반복실행 while, do, for 순차적수행선택적수행반복수행 문장 1 문장 2 No(False) 조건문장 1 Yes(True) 문장 2 Yes(True) 조건문장 1 No(False) 문장 2 24
선택적실행문 - if~then~else 주어진조건의참, 거짓여부에따라명령실행 예 : test_if if 조건명령 then [ else fi 명령 명령 ] ssh lily.mmu.ac.kr $./test_if Input x : 100 Input y : 200 x is less then y $ 25 엄밀히말하면조건명령을실행하여그실행값이 0 이아닌값이면 then 다음의명령을실행하고, 0 이면 else 다음의명령을실행한다. #!/bin/bash # test_if : if 문을테스트하는스크립트 print -n Input x : read x # x 값을입력받음 print -n Input y : read y # y 값을입력받음 if (( x < y )) then echo x is less than y else echo y is less than x fi
선택적실행문 - if~then~elif ~ else 조건이실패일때새로운분기명령실행 예 : test_elif if 조건명령 1 then 명령 elif 조건명령 2 then else fi 명령 명령 ssh lily.mmu.ac.kr $./test_elif Input Score : 50 Your score is not good. $ #!/bin/bash # test_elif: if-elif 문테스트 print -n Input Score : read score if (( $score > 90 )) then echo Your score is great. elif (( $score >= 80 )) then echo Your score is good. else echo Your score is not good. fi 26
조건테스트 - 문자열연산자 조건명령에사용하는문자열연산자 내장명령 [[ ]] 사용 문자열연산자 string = pattern string == pattern string!= pattern string 동작 string이 pattern과일치. = 연산자양쪽에공백 string이 pattern과일치하지않음 string이널이아님 -z string string의길이가 0 -n string string의길이가 0이아님 -l string string의길이 27
조건테스트 - 문자열연산자 예 : test_string #!/bin/bash # test_string: 문자열테스트스크립트 print -n "Are you OK (y/n)? " read ans if [[ $ans = [Yy]* ]] then print Happy to hear it. else print That is too bad. fi # ans 변수에값저장 # y로시작하는문자열인가 # y로시작하면 # y로시작하지않으면 28
조건테스트 - test 플래그 파일관련테스트 test 플래그 기능 -a file 파일이존재 -e file 파일이존재 -L file 심볼릭링크파일 -O file 사용자가 file의소유자 -G file 파일의그룹 ID가스크립트의그룹 ID와같음 -S file 소켓파일 29
조건테스트 - test 플래그 test 플래그 -r file 읽기가능 기능 -w file 쓰기가능 -x file 실행가능 -b file 블록장치특수파일 -c file 문자장치특수파일 -d file 디렉토리파일 -p file 파이프파일 -u file setuid 권한부여파일 -g file setgid 권한부여파일 -k file sticky bit 접근권한부여파일 -s file 파일의크기가 0이아님 30
조건테스트 - test 플래그 예 : test_file #!/bin/bash # test_file: 파일연산자테스트 print -n " 파일이름을입력하세요 : " read file if [[ -G $file ]] then print 그룹 ID 가같습니다. else print 그룹 ID 가같지않습니다. fi if [[! -a $file ]] then print 파일이존재하지않습니다. 파일이름을다시확인하세요. elif [[ -f $file ]] then print 일반파일입니다. elif [[ -d $file ]] then print 디렉토리파일입니다. else print 특수파일입니다. fi 31 ssh lily.mmu.ac.kr $./test_file 파일이름을입력하세요 : /dev/null 그룹 ID 가같지않습니다. 특수파일입니다 $./test_file 파일이름을입력하세요 :. 그룹 ID 가같습니다. 디렉토리파일입니다. $./test_file 파일이름을입력하세요 : /etc/hosts 그룹 ID 가같지않습니다. 일반파일입니다. $
선택적실행문 - case 문 주어진변수의값에따라실행할명령따로지정 변수의값이 value1 이면 value1 부터 ;; 을만날때까지명령실행 값의지정에특수기호, (or 연산자 ) 사용가능 일치하는값이없으면기본값인 * 부터실행 case 변수 in value1) 명령 ;; value2) 명령 ;; *) 명령 ;; esac 32
선택적실행문 - case 문 예 : test_case #!/bin/bash # case 테스트스크립트 print -n 명령을선택하세요 : read cmd case $cmd in [0-9]) # 0부터 9까지임의의숫자 date ;; "cd" "CD") # cd 또는 CD print $HOME ;; [aa-c]*) pwd ;; *) print Usage : 명령을선택하세요 ;; esac ssh lily.mmu.ac.kr # 소문자 a, 대문자 A,B,C 로시작하는임의의문자열 33 $./test_case 명령을선택하세요 : 5 Sunday, August 19, 2012 12:31: 35 AM KST $./test_case 명령을선택하세요 :cd /home/user1 $./test_case 명령을선택하세요 :a /home/user1/unix/ch13 $
반복실행문 - for 리스트안의각값들에대해지정한명령을순차실행 for 변수 in list do 명령 done Tip] list 대신 $(<file) 을사용하면외부파일의내용을입력으로받아서처리! 예 : test_for #!/bin/bash # test_for: for 테스트스크립트 for num in 0 1 2 do print number is $num done ssh lily.mmu.ac.kr $ test_for number is 0 number is 1 number is 2 $ 34
반복실행문 - for 명령행인자처리가능 예 : test_for3 #!/bin/bash # test_for3: 명령행인자처리 for person in $* do mailx $person < letter print ${person} 에게메일을보냈습니다. done print ---------------------------- print 모든메일을보냈습니다. ssh lily.mmu.ac.kr $./test_for3 user1 user2 user3 user1 에게메일을보냈습니다. user2 에게메일을보냈습니다. user3 에게메일을보냈습니다. ------------------------ 모든메일을보냈습니다. $ 35
반복실행문 - while 조건명령이정상실행되는동안명령반복 while 조건명령 do done 명령 예 : test_while #!/bin/bash # test_while: while 을이용해 1 부터 10 까지합을구하는스크립트 count=1 sum=0 while (( count <= 10 )) do (( sum += count )) let count+=1 done print 1 부터 10 까지의합 : $sum ssh lily.mmu.ac.kr $ test _while 1 부터 10 까지의합 : 55 $ 36
반복실행문 - until 조건명령이정상실행될때까지명령반복 until 조건명령 do done 명령 예 : test_until ssh lily.mmu.ac.kr $./test_until 로그인이름 : hanb hanb pts/3 Aug 19 01:07 (192.168.0.2) $ #!/bin/bash # test_until: 지정한사용자가로그인하면알리는스크립트 print -n 로그인이름 : " # 입력안내문출력 read person # 유저이름을 person에저장 until who grep $person # > /dev/null do sleep 5 # 유저가접속중이아니면 5초쉼 done print "\007" # beep. 삑소리를냄 37
반복실행문 - select 메뉴를생성할수있는반복실행문 list 에지정한항목을자동으로선택가능한메뉴로만들어화면에출력해줌 사용자는각항목에자동부여된번호를선택 사용자입력은 select 와 in 사이에지정된변수에저장 보통 case 문과결합하여입력값처리 select 변수 in list do done 명령 사용자입력값저장 일반적으로 case 문사용 자동메뉴생성목록 38
반복실행문 - select 예 : test_select ssh lily.mmu.ac.kr $ test _select 1) pwd 2) date 3) quit 명령을입력하세요 : 1 /export/home/user1/unix/ch13 1) pwd 2) date 3) quit 명령을입력하세요 : 3 $ #!/bin/bash # test_select: 사용자입력에따라 pwd,date 명령실행 PS3=" 명령을입력하세요 : " select cmd in pwd date quit do case $cmd in pwd) pwd ;; date) date;; quit) break;; *) print 잘못입력하셨습니다. 번호를선택하세요. ;; esac REPLY= done 39
루프제어문 - continue 루프안에서사용 이후실행순서를무시하고루프의처음으로돌아가는명령 숫자를지정하면중첩된루프안에서특정루프의처음으로돌아갈수있음 예 : test_cont #!/bin/bash # test_cont: continue 테스트 for person in $(< list) # `cat list`와동일 do if [[ $person == user2 ]] then continue # user2 이면건너뜀 fi mailx -s continue test $person < letter print ${person} 에게메일을보냈습니다. done print -------------------------- print 모든메일을보냈습니다. 40
06. 함수 함수 : 하나의목적으로사용되는명령들의집합 앨리어스와의차이점 조건에따라처리가능 function 함수이름 인자처리가능 { 명령들 } 예 : trash ssh lily.mmu.ac.kr $ mkdir ~/.TRASH $ function trash { > mv $* ~/.TRASH > } $ 41
함수확인및호출 정의된함수확인 ssh lily.mmu.ac.kr $ typeset -f trash() { mv $* ~/.TRASH } $ 함수호출 ssh lily.mmu.ac.kr $ touch a b c $ ls a b c $ trash a b c $ ls $ ls ~/.TRASH a b c $ 42
함수종료조건 함수의종료 - return 함수본문안의마지막문장실행 return 문실행 return [ n ] 지정한값이함수의종료값으로 $? 에저장됨 43
예 : test_add #!/bin/bash # 함수리턴값테스트 function sum { typeset sum 함수의종료 - return } (( sum= $1 + $2 )) return $sum sum $1 $2 print $1 + $2 = $? ssh lily.mmu.ac.kr $ add 3 4 3 + 4 = 7 $ 44
함수삭제 - unset unset -f 함수명 정의된함수를삭제 사용예 ssh lily.mmu.ac.kr $ unset -f trash $ functions $ 45
07. 디버깅 스크립트실행도중발생한오류수정방법 구문오류 쉘이실행도중구문오류가발생한라인번호출력 실행오류 오류메시지없이실행이안되거나비정상종료 오류수정방법 bash -x, trap 46
디버깅 : bash -x 가장간단한스크립트실행오류수정방법 스크립트의각행이실행될때마다화면에출력됨 ssh lily.mmu.ac.kr $ bash -x test_while + count=1 + sum=0 + (( count <= 10 )) + (( sum+=count )) + let count+=1 + (( count <= 10 )) + (( sum+=count )) + let count+=1 + (( count <= 10 )) ( 중략 ) + print 1 부터 10 까지의합 : 55 1 부터 10 까지의합 : 55 $ 47 스크립트의내용
디버깅 : trap 지정한시그널이스크립트로전달될때마다지정한명령실행 스크립트의명령이한줄씩실행될때마다 DEBUG 시그널이스크립트로전달됨 DEBUG 시그널을받을때마다원하는변수값출력가능 trap 명령시그널 스크립트가실행되는도중변수값확인 48
예 : test_trap #!/bin/bash # test_trap: trap 테스트스크립트 디버깅 : trap trap print $LINENO : count=$count DEBUG count=1 sum=0 while (( count <= 10 )) do (( sum += count )) let count+=1 done print 1 부터 10 까지의합 : $sum ssh lily.mmu.ac.kr $./test_trap 6 : count= 7 : count=1 9 : count=1 11 : count=2 12 : count=2 ( 중략 ) 9 : count=11 15 : count=11 1 부터 10 까지의합 : 55 $ 49
13 장요약 [1/3] 쉘스크립트개요 쉘이제공하는프로그래밍구문과유닉스명령으로구성된텍스트파일 실행방법 : $ bash script 또는 $chmod +x script $ script 쉘변수사용하기 변수정의 : 변수명 = 값 다양한변수표현방법, 변수문자열처리방법이있음 명령행인자는위치매개변수를이용하여처리 ($0, $1,..) 사용자입력처리 키보드입력처리 : read 스크립트에서입력처리 : here 문서 연산자 산술, 비교, 논리, 비트연산지제공 사용방법 : let 다음또는 (( )) 안에연산식기술 50
13 장요약 [2/3] 조건문 반복문 함수 if 문 : if 다음의명령을실행한종료값이 0 이면 then 다음을, 0 이아닌값이면 else 다음을실행 case 문 : 변수의값에따라선택적으로명령실행 for 문 : 리스트에있는값을순차적으로변수에저장하여명령실행 while 문 : 조건명령이성공인동안명령반복실행 until 문 : 조건명령이실패인동안명령반복실행 select 문 : 선택가능한메뉴를생성하는반복문. 선택에따른동작을지정하려면 case 문과함께사용해야 하나의이름으로실행할수있는명령의집합으로인자전달가능 함수정의 : $ function foo { date; cal; } 함수호출 : $ foo 함수삭제 : $ unset -f foo 51
디버깅 13 장요약 [3/3] 스크립트의실행오류수정방법 bash -x script : 지정한 script 를한행씩실행하며결과를화면에출력 trap 명령 DEBUG : trap 을포함한스크립트를한행씩실행할때마다 trap 안에기술한명령을실행 52