제어구조 쉘에서사용되는제어구조 if,while,case,switch,for 등다양 Chapter 7. 본쉘프로그래밍 (2) 쉘마다지원되는기능이조금씩다르다 7.1 쉘의제어구조 7.2 디버깅 2 if 문 if 다음의조건식이참 (true) 이면 뒤의명령어들을실행하라는의미 조건이비교될때결과값이 0 이면참으로인식 if [ 조건 ] 조건이참이면명령들을수행 if 문 $ vi if_test.sh if [ $1 -gt 0 ] " 입력한 $1 은양수입니다 " $ chmod +x if_test.sh $./if_test.sh10 입력한 10 은양수입니다 그림 7-1. if 문사용예 (1) 3 4
if else 문 조건문이참이면 아래의명령어들이수행되고그렇지않을경우 else 다음명령어들이수행 if [ 조건 ] 조건이참이면명령어1들을수행 else 조건이거짓이면명령어2들을수행 if else 문 $ vi if_test2.sh if test -f $1 $1 exit else $1 not exit $ chmod +x if_test2.sh $./if_test2.sh ttt ttt not exit $./if_test2.sh le1 le1 exit 그림 7-2. if 문사용예 (2) 5 6 if elif 문 조건 1 이참이면 다음명령들이수행되고조건 2 가참이면그뒤의 다음명령어가, 조건1, 조건2가참이아니면 else 다음명령어를수행 if [ 조건1] 조건 1 이참이면명령들을수행 elif [ 조건2] 조건 2 가참이면명령들을수행 else 조건1, 조건2가거짓이면명령들을수행 if elif 문 $ vi if_test3.sh if [ $# -ge 2 ] $2 elif [ $# -eq 1 ] $1 else No Input $ chmod +x if_test3.sh sh $./if_test3.sh a b b $./if_test3.sh sh a a $./if_test3.sh No Input 7 그림 7-3. if 문사용예 (3) 8
test 문 test t 또는 [] 연산자를사용하여조건문의참, 거짓을평가함 조건이참이면종료상태가 0(true) 으로지정되며, 거짓이면종료상태가 0 이아닌값으로지정 형식 : test - 옵션파일명 test 문 test 문의옵션들 옵션 결과가참이되기위한조건 -r 파일이존재, 읽기가능하면반환값 true(0) -w 파일이존재, 쓰기가능하면반환값 true(0) -x 파일이존재, 실행가능하면반환값 true(0) -f 파일이존재, 정규파일이면반환값 true(0) -d 파일이존재, 디렉터리이면반환값 true(0) -h, -L 파일이존재, 심볼릭링크 ( 소프트링크 ) 이면반환값 true(0) -c 파일이존재, 문자특수파일이면반환값 true(0) -b 파일이존재, 블록특수파일이면반환값 true(0) -p 파일이존재, 네임드파이프이면반환값 true(0) -s 파일이존재, 크기가 0 초과하면반환값 true(0) 9 10 test 문 cecom% cat letest.sh if test -r $1 ; readable if test -w $1; writable if [ -x $1 ] ; executable cecom% letest.sh letest.sh readable writable executable cecom% letest.sh. readable writable executable cecom% 다음과같은상태검사를하는각각 3 개의쉘스크립트를작성하라. [ 형식 ] ss.sh <lename> 1. 쉘스크립트1(ss1.sh): 읽기가능, 쓰기가능, 수행가능을판별하는기능 2. 쉘스크립트2(ss2.sh): 정규화일, 디렉토리, 심볼릭링크인지판별하는기능을가진쉘스크립트 3. 쉘스크립트3(ss3.sh): 문자특수화일, 블록특수화일, 네임드파이프인지판별하는기능을가진쉘스크립트 11 12
1. 쉘스크립트 1(ss1.sh): sh): 읽기가능, 쓰기가능, 수행가능을판별하는기능 if [ $# -lt 1 ] "few argument" if [ -r "$1" ] "$1 is readable" if [ -w "$1" ] "$1 is writable" if [ -x "$1" ] "$1 is executable" 1. 쉘스크립트 1(ss1.sh): sh): 읽기가능, 쓰기가능, 수행가능을판별하는기능 if [ $# -lt 1 ] "few argument" if [ -r "$1" ] "$1 is readable" if [ -w "$1" ] "$1 is writable" if [ -x "$1" ] "$1 is executable" 13 14 2. 쉘스크립트 2(ss2.sh): sh): 정규화일, 디렉토리, 심볼릭링크인지판별하는기능을가진쉘스크립트 if [ $# -lt 1 ] if [ -h "$1" ] few argument if [ -f "$1" ] "$1 is regular le" if [ -d "$1" ] "$1 is directory" if [ -L "$1" ] "$1 is symbol link(-l)" "$1 is symbol link(-h)" 15 3. 쉘스크립트 3(ss3.sh): sh): 문자특수화일, 블록특수화일, 네임드파이프인지판별하는기능을가진쉘스크립트 if [ $# -lt 1 ] few argument if [ -b "$1" ] "$1 is block special le" if [ -c "$1" ] "$1 is character special le" if [ -p "$1" ] "$1 is named pipe" 16
test 문 test 문 test 문의논리연산 옵션! 부정 (NOT) -a AND -o OR cecom% cat logictest.sh if test -r $1 -a -x $1 ; readable, writable 의미 cecom% chmod +x logictest.sh cecom% %logictest.sh t. readable, writable cecom% test 문의문자열을위한옵션 옵션 결과가참이되기위한조건 -z 문자열 문자열의크기가 0 -n 문자열 문자열의크기가 0이아님 문자열1 = 문자열2 문자열1과문자열2가같음 문자열1!= 문자열2 문자열1과문자열2가다름 문자열 문자열이 NULL 아님 17 18 test 문 cecom% cat stringtest.sh 문자열을받아들여다음과같은상태검사를하는쉘스크립트를작성하라. if test -z $1 ; length is 0 if test -n $1 ; length is not 0 if test $0 = $1 ; equal! if test $0!= $1 ; not equal! cecom% chmod +x stringtest.sh cecom% stringtest.sh tea length is not 0 not equal! cecom% stringtest.sh stringtest.sh length is not 0 equal! cecom% [ 형식 ] stringstest.sh <arg1> <arg2> arg1 하나만있을경우 1. 문자열의크기가 0인가를테스트후메시지프린트 2. 문자열의크기가 0 이아닌지를테스트후메시지프린트 arg1,arg2 g 두개가있을경우 1. 문자열 arg1, arg2가같은지비교후메시지프린트 2. 문자열이 stringstest.sh와이름이같은지비교후메시지프린트 19 20
test 문 Example 7-5. Arithmetic and string comparisons #!/bin/bash / test 문의정수비교옵션 옵션 n1 eq n2 n1 ne n2 n1 gt n2 n1 ge n2 n1 lt n2 n1 le n2 n1 = n2 n1!= n2 n1 > n2 n1 >= n2 n1 < n2 n1 <= n2 의미 a=4 b=5 # Here "a" and "b" can be treated either as integers or strings. # There is some blurring between the # arithmetic and string comparisons, #+ since Bash variables are not strongly typed. # Bash permits integer operations and # comparisons on variables #+ whose value consists of all-integer characters. # Caution advised, however. if [ "$a"!= "$b" ] "$a is not equal to $b." "(string comparison)" # "4"!= "5" # ASCII 52!= ASCII 53 # In this particular instance, # both "-ne" and "!=" work. exit 0 21 if [ "$a" -ne "$b" ] "$a is not equal to $b" "(arithmetic comparison)" 22 test 문 cecom% cat numtest.sh if test $1 -ge 90 ; Grade is A elif [ $1 -ge 80 ] ; Grade is B elif test $1 -ge 70 ; Grade is C elif test $1 -lt 60 ; Grade is F cecom% numtest.sh 12 Grade is F cecom% numtest.sh 96 Grade is A cecom% numtest.sh sh 87 Grade is B cecom% case 문 단일문자열의값에근거한다중선택의분기를지원. Bourne 쉘에서는 case를, C 쉘에서는 switch를사용 sh의 case문 문법구조 : case 스트링 in 패턴1) command list ;; 패턴 2) command list ;;. 패턴 n) command list ;; esac Parameter( 스트링 ) 와일치하는패턴을가진명령행이수행패턴검색에는와일드카드 (?, *) 가사용가능 23 24
case 문 #casetest.sh case $1 in aa ab) A ;; b?) "B\c" $1;; c*) C;; *) D;; esac [/home1/gilng/unix2/scripts]% chmod +x casetest.sh [/home1/gilng/unix2/scripts]% casetest.sh D [/home1/gilng/unix2/scripts]% casetest.sh bb Bbb [/home1/gilng/unix2/scripts]% casetest.sh ab A [/home1/gilng/unix2/scripts]% 25 case 문 $ vi case2_test.sh sh case $1 in aa ab) A ;; b?) "B c" $1 ;; c*) C ;; *) D ;; esac $ chmod +x case2_test.sh $./case2 _test.sh D $./case2_test.sh ab A $./case2_test.sh bb Bbb 그림 7-9. case 문에서패턴검색에와일드카드사용예 26 Example 10-25. Creating menus using case #!/bin/bash # Crude address database clear # Clear the screen. " Contact List" " ------- ----" "Choose one of the following persons:" "[E]vans, Roland" "[J]ones, Mildred" "[S]mith, Julie" "[Z]ane, Morris" read person case "$person" in # Note variable is quoted. "E" "e" ) # Accept upper or lowercase input. "Roland Evans" "4321 Flash Dr." "Hardscrabble, CO 80753" "(303) 734-9874" "(303) 734-9892 fax" "revans@zzy.net" "Business partner & old friend" ;; # Note uble semicolon to terminate each option. 27 "J"" "j" "" ) "Mildred Jones" "249 E. 7th St., Apt. 19" "New York, NY 10009" "(212) 533-2814" "(212) 533-9972 fax" "milliej@loisaida.com" "Ex-girlfriend" * ) # Default option. # Empty input (hitting RETURN) ts here, too. "Not yet in database." ;; esac "Birthday: Feb. 11" ;; # Add info for Smith & Zane later. # Exercise: # -------- # Change the script so it accepts multiple inputs, #+ instead of terminating after displaying just one address. exit 0 28
# casetest.sh 아래와같은메뉴를프린트하고메뉴에맞는동작을하는쉘프로그램을작성하라. #./casetest1.sh " select number. [1] make directory [2] remove le [3] list current directory? 2 1~3 입력 remove le enter lename: testle removed # 지우고자하는화일이름입력 화일이름없이그냥엔터를치면 not entered 출력하고마침 29 " select number." " [1] make directory " " [2] remove le" " [3] list current directory" -n "?" read number case $number in "1") "make directory" -n "enter directory name: " read dirname if [! -z $dirname ] mkdir $dirname "maded..." else "not entered ;; "2") "remove le" -n "enter lename: " read lename if [! -z $lename ] rm -rf $lename "removed..." else "not entered" ;; "3") list=`ls` $list ls -al ;; *) "wrong selection";; esac 30 for 문 for 문 각반복기간동안, 반복변수의다른값을사용하여명령의목록이여러차례실행되도록함 단어리스트에있는각각의단어값을변수값으로할당하여명령어리스트들을실행 문법구조 : for 변수 [ in 단어 1, 단어 2,, 단어 n ] 명령리스트 ne cecom% chmod +x fortest.sh / cecom% %fortest.sh t #fortest.sh a.old b.old for le in *.old c.old cecom% $le ne in 다음에설정된변수리스트의값이변수에할당되는동안 에서 ne 까지의명령행이수행 31 32
for 문 $ vi for3_test.sh for le $le ne $ chmod +x for3_test.sh sh $./for3_test.sh le? le1 le2 le3 le4 그림 7-11. for 문의 in 뒤에단어가생략된예 Example 10-1 1. Simple for loops #!/bin/bash # Listing the planets. for planet in Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto $planet # Each planet on a separate line. ne ; for planet in "Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto" # All planets on same line. # Entire 'list' enclosed in quotes creates a single variable. # Why? Whitespace incorporated into the variable. $planet ne ; "Whoops! Pluto is no longer a planet!" 33 exit 0 34 - 답 현재디렉토리에있는모든파일과디렉트리에대해서화일이면에 [f] < 화일이름 > 디렉토리이면 [d] < 디렉토리이름 > 로프린트하는쉘프로그램을작성하라. # ls abc def abc1 testle #./ls1.sh [f] abc 화일인경우 [d] def 디렉토리인경우 [d] abc1 [f] testle # for lename in * if [ -f $lename ] "[f] $lename" if [ -d $lename] "[d] $lename" ne 35 36
현재디렉토리에있는모든파일과디렉트리에대해서화일이면에 [f] < 화일이름 > 디렉토리이면 [d] < 디렉토리이름 > 로프린트하고디렉토리일경우내부로들어가파일과디렉토리를프린트하는프로그램을작성하라. # nd../dir1./dir1/le3./dir1/le4./dir2./dir2/le5./dir3./dir3/dir4 /./dir3/dir4/dir5./dir3/dir4/dir5/le5./le1./le2./ls2.sh #./ls2.sh [d] dir1 [f] le3 [f] le4 [d] dir2 [f] le5 [d] dir3 [d] dir4 [d] dir5 [f] le5 [f] le1 [f] le2 [f] ls2.sh [ 수행예제 ] # cat subshell.sh (cd /usr; ls) (cd /usr/bin; ls) "end" - 답 for lename in * if [ -f $lename ] "[f] $lename" if [ -d $lename ] "[d] $lename" (cd $lename; ls2.sh) ne 37 38 while 문 문법구조 : while 조건 명령리스트 [break] [continue] ne #whiletest.sh while [ $# -gt 0 ] $1 shift ne 조건이참인동안 와 ne 사이의명령행수행 break 명령은강제로 while문을종료할때사용 continue 는강제로다음조건을비교하고자할때사용 while 문 $ vi while1_test.sh while [ $# -gt 0 ] $1 shift ne $ chmod +x while1_test.sh $./while1_test.sh one two three four ve one two three four ve 그림 7-12. while 문사용예 39 40
Example 10-14. Simple while loop emailto: mylecture.three@gmail.com TITLE: UNIX SYSTEM LAB 2009-00-00 < 이름 > #!/bin/bash # Equivalent to: while [ "$var1"!= "end" ] # while test "$var1"!= "end" "Input variable #1 (end to exit) " read var1 # Not 'read $var1' (why?). "variable #1 = $var1" # Need quotes because of "#"... # If input is 'end', es it here. # Does not test for termination condition until top of loop. ne exit 0 아래와같은메뉴를프린트하고메뉴에맞는동작을하는쉘프로그램을작성하라. #./casetest1.sh " select number. [1] make directory [2] remove le [3] list current directory [4] exit? 2 1~3 입력 remove le enter lename: testle 지우고자하는화일이름입력화일이름없이그냥엔터를치면 not entered 출력하고마침 removed 41 42 -while -while # cat while_test1.sh while read line line if [! $data ] break; ne 어떤 (note.l) 화일을읽어서아래와같이프린트하는스크립트를작성하라. #./while_test1.sh note.l {{{{{{{}}}}}}} ********** ============== ++++++++++++++ ----------- # cat note.l brace star equal plus line 43 44
until 문 until 문은 Bourne 쉘에서만사용가능 문법구조 : until 조건 조건이거짓인동안명령리스트수행 ne #untiltest.shsh until [ $# -le 0 ] $1 shift ne 조건이거짓인동안 에서 ne 사이의명령이실행 [/home1/gilng/unix2/scripts]% chmod +x untiltest.sh [/home1/gilng/unix2/scripts]% untiltest.sh one two three one two three [/home1/gilng/unix2/scripts]% #!/bin/bash END_CONDITION=end until [ "$var1" = "$END_CONDITION" ] # Tests condition here, at top of loop. "Input variable #1 " "($END_CONDITION to exit)" read var1 "variable #1 = $var1" ne 45 46 수식계산 # cat exptest.shsh #./exptest.sh sh b=$a+1-->1+1 b=`expr $a + 1`-->2 a=1 b=$a+1-->1+1 b=$(($a+1))-->2 b=$a+1 -n n'b 'b=$a+1-->' $b b= ` expr $a + 1` -n 'b=`expr $a + 1`-->' $b 아래와같은 1부터 100 까지프린트하는프로그램을작성하라. #./number.sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 # sh number.sh 123456789101112131415161718192021222324252627282930313233 10 11 13 14 15 16 17 18 19 20 21 22 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 b=$a+1 -n 'b=$a+1-->' $b b=$(($a+1)) -n 'b=$(($a+1))-->' $b 47 48
break, continue 문 break, continue 문 break, continue 문은제어구조인 for, while, until 문과같이반복적인명령실행을중지하거나그다음반복을수행하는데사용 $ vi break_test.sh sh "Do you like Bourne shell please answer yes/no or y/n: c" read answer break 반복 (loop) 되는실행과정을빠져나오는명령 continue 반복과정을벗어나지않고루프의변수를다음값을가지게하고, 그다음반복수행을하게함 49 case $answer in "yes" "y" "YES") "You like Bourne shell" break ;; [nn]*) "You not like Bourne shell" break ;; *) "Error, please answer only yes/no or y/n" break ;; esac $ chmod +x break_test.sh $./break_test.sh Do you like Bourne shell please answer yes/no or y/n: y You like Bourne shell 50 break, continue 문 break,continue example-try $ cat > students blackjo white brown robin shcho john ^D $ vi continue_test.sh for name in `cat students` if [ "$name" = "shcho" ] continue else $name ne 51 Example 10-20 20. Effects of break and continue in a loop #!/bin/bash LIMIT=19 "Printing Numbers 1 through 20 (but not 3 and 11)." a=0 while [ $a -le "$LIMIT" ] a=$(($a+1)) if [ "$a" -eq 3 ] [ "$a" -eq 11 ] continue -n "$a ne Printing Numbers 1 through 20, but something happens after 2. a=0 while [ "$a" -le "$LIMIT" ] a=$(($a+1)) if [ "$a" -gt 2 ] break -n "$a " ne exit 0 52
exit 문 다른제어문과함께사용될수있는명령강제로스크립트를종료할때사용 문법구조 : exit [result] result 의값이 0 이면참을그렇지않으면거짓을의미 만약생략될경우 exit 이전에실행한명령이반환한값 / #ifexit.sh if [ $# -eq 0 ] "enter lename" exit 1 else exit 0 exit 문 $ vi exit_test.sh if test -f $1 " $1 is exists" exit 3 $ chmod +x exit_test.sh $ ls le1 le2 le3 le4 $./exit_test.sh le1 le1 is exists $ $? 3 그림 7-16. exit 사용예 (1) 53 54 trap trap 명령어 < <signal l#> # cat trap_test.sh trap control-c; exit 1 2 while true innite loop sleep 2 ne # chmod +x trap_test.sh #./trap_test.sh t t -> 수행중 control-c 입력으로테스트 함수 (function) 본쉘에서는함수를정의할수있음 csh 의 alias 와비슷한함수제공 선언형식 func_name() { 수행문장들 ; } 중괄호 '{' 다음엔반드시공백 반드시세미콜론 ';' 포함반드시빈칸을두어야한다!! #func.sh ls() { /bin/ls -la "$@"; } 반드시 "My rst function" 포함되어야 ls # 함수호출한다!! "Function terminated" 55 56
함수 ( 지역변수와전역변수 ) 함수 지역변수란함수내에서정의된변수 함수내에서만의미가있고함수를벗어나면의미가없는변수 전역변수란전체스크립트에서의미가있는변수 #func_var.sh 전역변수로선언하였다! $ vi f1_test.sh rst() { "shell script function is executing" } msg="global variable" ls() { } msg="local variable" /bin/ls / -la "$@"; $msg 지역변수로선언하였다! "My second function" $msg ls # 함수호출 "Function terminated" $msg exit 0 57 "my rst function" rst "function terminated" $ chmod +x f1_test.sh $./f1_test.sh my rst function shell script function is executing function terminated 그림 7-20. 함수사용예 58 Example 23-1. Simple functions #!/bin/bash JUST_A_SECOND=1 funky () { # This is about as simple as functions get. "This is a funky function." "Now exiting funky function. " } # Function declaration must precede call. while [$ $i -lt $REPEATS ] "-------FUNCTIONS---------->" "<--------ARE-------------" "<-------FUN------------>" let "i+=1" ne } 인수와반환값 #Example 23-1. Simple functions #!/bin/bash funky () { # This is about as simple as functions get. "This is a funky function." return 0 } # Function declaration must precede call. exit 0 funky if [ $? -eq 0 ] "SUCCESS" fun 2 3 result is $?" fun () { # A somewhat more complex function. i=0 REPEATS=30 # Now, call the functions. funky fun fun () { i=0 REPEATS=30 "And now the fun really begins." sleep $JUST_A_SECOND # Hey, wait a second! exit 0 59 } "This is a fun function." let "i=$1+$2" return $i 60
디버깅 스크립트작성시간의많은부분을오류찾는데소모가장단순한방법은 명령어를이용하는것 쉘은자체적으로디버그모드를포함 문법적인오류만을체크 sh xx 옵션사용 ( 교재참고 ) x 옵션을사용하여스크립트를실행하고변수와미리정의된지역변수등이적용되어실행된모든과정들을보여줌 문법적인오류가없을경우, 모든수행과정들을분석하여문제점을파악해야함 61