Chapter 11 The C Shell
Contents History Alias Directory stack User variables Shell variables C shell script Control structure 이 장에서 배우는 C shell 의 특징으로는 history, alias, directory stack 등의 기능이 있습니다. C shell에서의 user variable 사용법, C shell에서 사용하는 shell variable들에 대해서 알아 봅니다. 대표적인 C shell script인 .login, .cshrc, .logout등에 대해서 알아보고, shell script에서 사용할 수 있는 제어구조에 대해서 알아 봅니다.
The C Shell 실수 방지, 쉬운 사용법 제공. alias와 history 기능 등으로 인하여 로그인 쉘로 많이 사용됨. Bourne shell은 프로그래밍 언어로 많이 사용 C shell의 호출 csh C shell의 이탈 ^D (unset ignoreeof) exit logout C shell은 위에 있는 특징때문에 주로 로그인 쉘로 사용됩니다. 몇 가지 버그(지금은 고쳤겠지만)와 alias기능, Bourne shell보다 못한 프로그래밍 편의성 때문에 프로그래밍으로는 잘 사용하지 않았다는 군요. ignoreeof는 on/off 형태의 값을 갖는 쉘변수로서 뒤에 다시 나옵니다. ^D - ignoreeof 가 set 되어 있지 않을 때, shell 을 빠져 나옴 ignoreeof 가 set 되어 있을 때, 무시하고 메시지 출력 (Use exit to leave csh) exit - 항상 shell을 빠져 나옴. logout - login shell이면 logout login shell이 아니면, 무시하고 메시지 출력(not login shell)
History(1) 최근에 수행된 명령어(event)의 리스트를 간직하고 이들을 그대로 또는 변형하여 다시 사용할 수 있는 방법을 제공 $history - history 리스트의 크기 % set history=10 % history 23 cat tmp ….. 30 rm memo 31 set history=10 32 history
History(2) 명령어의 재실행 변형된 명령어의 사용 바로 전의 명령 재실행 !! 명령의 절대적 번호 사용 !3 바로 전의 명령 재실행 !! 명령의 절대적 번호 사용 !3 명령의 상대적 번호 사용 !-5 명령어의 텍스트 사용 !ps 변형된 명령어의 사용 % car /home/jenny/memo.0507 /home/alex/letter.0507 car: Command not found. % !!:s/car/cat % ^car^cat cat /home/jenny/memo.0507 /home/alex/letter.0507 !-1은 바로 지난번의 명령어입니다. 즉 !! 와 동일. 위의 예에서는 !!:s/car/cat 와 ^car^cat은 같은 의미입니다. !!:s/ca?/cat 와 같은 정규표현은 사용할 수 없습니다. ^car^cat 와 !!:s/car/cat은 한번만 대치가 가능합니다. 예를 들어, car xxx; car xxx인 경우, ^car^cat --> cat xxx; car xxx 입니다. 모두 바꾸고 싶으면 !!:gs/car/cat --> cat xxx; cat xxx 입니다 이 외에도, 교재에는 modifier가 몇 가지 더 있는데, 굳이 할 필요는 없군요.
Alias(1) % alias dir ls -al ; short name for commands % alias mi mv -I ; protect from mistakes % alias head sed 10q ; create new commands % alias ; display the alias list % alias head ; display the alias for ‘head’ % unalias head ; remove an alias for ‘head’ % alias a b % alias b c % alias c echo finished % a finished 위에서부터 3개의 명령은 alias의 사용 목적과 설정방법을 말합니다. 그 다음 3개의 명령은 설정된 alias의 표시와 취소방법입니다. 나머지는 alias의 동작 방법입니다. 사용자가 명령을 내리면, C shell은 명령어와 인수로 나눕니다. 그리고 나서 각각의 명령어를 더 이상 alias가 존재하지 않을 때가지 계속 대치를 합니다. 즉 위의 예에서는 a-->b-->c로 대치된 것입니다. 만약 위의 예에서, alias c a 라고 한다면 어떻게 될까요? a-->b-->c-->a-->b…. 이렇게 되겠죠. 하지만 C shell은 대치를 해 나가다가, 루프를 발견하면 더 이상 진행하지 않고 Alias loop라는 메시지를 출력합니다.
Alias(2) argument의 전달 \!* : 모든 argument \!^ : 첫번째 argument % alias loc ‘find . -name “*.c” -print | xargs grep \!*’ % loc strcmp find . -name “*.c” -print | xargs grep strcmp 위의 예에서 xargs 는 표준입력을 grep 의 마지막 인수로 넘겨줍니다. 즉, find . -name “*.c” -print는 현재 디렉토리의 하위에 있는 모든 디렉토리에서 .c 파일을 모두 찾아 그 이름을 출력합니다. 이 출력은 xargs에 의해 grep 의 마지막 인수로 전달이 됩니다. 이 때, grep 의 첫번째 인수는 \!*이 되고, 두번째 인수는 xargs로부터 넘겨받은 파일 이름입니다. 이제 grep은 각각의 .c 파일에서 \!*라는 패턴을 찾아 그 줄을 출력합니다.위 예에서 \!*은 strcmp가 되겠죠. 결국, loc 은 하위 디렉토리에 있는 모든 .c 파일에서 strcmp라는 패턴을 찾는 것입니다. !* 앞에 \를 붙인 이유는, \가 없으면 !*를 이전 명령어의 인수로 해석을 하기 때문입니다.
작업 제어 (Job control) background foreground % jobs ; list current jobs % fg %2 ; move job 2 into the foreground foreground background % ^Z % bg % stty tostop ; stop when try to write to terminal % notify %2 ; notify change in state stty -tostop은 background로 실행한 프로세스가 화면으로 출력을 할 수 있게 합니다. stty tostop은 background로 실행한 프로세스가 화면으로 출력을 원할 때, stop 시킵니다. 화면이 원치 않는 출력과 섞이지 않게 합니다. 하지만 이렇게 하면 프로세스가 stop이 되었는지 알 수가 없죠. 그래서 notify와 같이 사용합니다. 예를 들어, notify %1는 1번 작업 프로세스의 상태가 변하면(running --> stop) 이를 알려줍니다. 쉘변수 notify도 거의 같은 기능을 하는데 뒤에 나옵니다.
>&, ~, <ESC> 표준에러 파일 재지정 ( >& ) 파일명의 생성 ( ~ ) 파일명 완성 % cat x y >& hold % find / -name bibliography -print >& find.out & 파일명의 생성 ( ~ ) ~는 홈디렉토리의 경로명 생성 % cp idea.txt ~jenny 파일명 완성 % set filec % cat triglA <ESC> cat triglA302488 When ambiguous, press ^D to list matching file names. >& 는 표준출력과 표준에러를 하나의 파일로 재지정하는 것입니다. Bourne shell의 1>, 2>와 같이 서로 분리해서 재지정할 수는 없습니다. 하지만 다음과 같이 하면 같은 효과를 볼 수 있습니다. % (cat x y > hold) >& hold1 --> C shell $ cat x y 1> hold 2> hold1 ---> Bourne shell ~는 자신의 홈디렉토리 경로 생성 (예를들면, /home/alex) ~jenny 는 다른 사용자의 홈디렉토리 경로 생성 (예를 들면, /home/jenny) ~의 기능은 쉘변수 noglob으로 on/off 할 수 있습니다. 뒤에 나옵니다. 쉘변수 filec는 ESC에 의한 파일명 완성을 on/off 합니다. ^D는 매치되는 파일이름이 여러 개 있을 때, list를 보여 줍니다. 예를 들어, % ls test.c test.out a.out tmp.$$$ % cat test<ESC> --> 삐~ 하는 소리가 나죠 % cat test<^D> test.c test.out
디렉토리 스택의 사용(1) % dirs % pushd ../demo % pushd % popd 스택의 내용을 표시 디렉토리를 변경하고 새로운 디렉토리를 스택의 top에 추가 % pushd 두 번째 디렉토리를 작업 디렉토리로 두 디렉토리 사이의 이동에 사용 % popd 스택의 최상위 디렉토리를 제거하고, 새로운 top 디렉토리를 작업 디렉토리로 지정 pushd를 안 해도 현재 디렉토리는 항상 stack top에 자동으로 들어갑니다. cd 를 사용하면 항상 stack top만 자동으로 바뀝니다. pushd, popd는 명령을 수행한 후, 디렉토리 스택을 보여 줍니다. 다음 페이지에 자세한 예가 있습니다.
디렉토리 스택의 사용(2) % dirs ~/literature % pushd ../demo ~/demo ~/literature % pushd ../names ~/names ~/demo ~/literature % pushd ~/demo ~/names ~/literature names literature names demo literature demo names literature names demo % popd ~/names ~/demo names demo demo % pushd ~/names ~/demo ~/literature literature 애니메이션이 들어 있습니다. 슬라이드 쇼로 확인하세요. % dirs - 현재 디렉토리는 literature이고 스택에 있습니다. % pushd ../demo - demo로 디렉토리를 이동하고, stack top에 저장. % pushd ../names - names로 디렉토리를 이동하고, stack top에 저장. % pushd - 스택의 2번째 디렉토리(바로 전 디렉토리-demo)로 이동하고 스택의 1번째(names)과 2번째(demo) 디렉토리를 바꾼다. % pushd - 스택의 2번째 디렉토리(바로 전 디렉토리-names)로 이동하고 스택의 1번째(demo)과 2번째(names) 디렉토리를 바꾼다. 즉, 이렇게 하면 두 디렉토리를 pushd만으로 왔다 갔다 할 수…. % pushd +2 - stack top부터 차례대로 0, 1, 2…의 번호가 붙습니다. 따라서, +2은 3번째 디렉토리인 literature를 말합니다. 3번째 디렉토리(literature)로 이동하고, literature를 stack top으로 % popd - 스택의 1번째 디렉토리(literature)를 제거하고, 다음 디렉토리(names)로 이동 % pushd +2 ~/literature ~/names ~demo
변수(1) set : nonnumeric string의 지역변수 선언 @ : numeric의 지역변수 선언 setenv : 전역변수 선언(Bourne shell의 export와 유사) % set name=fred ; spaces are allowed around = % echo $name fred % unset name C shell의 사용자 정의 변수는 nonnumeric string 변수와 numeric 변수가 있습니다. Bourne shell에서는 스트링 변수만 있기 때문에, 숫자 계산을 하기 위해서는 expr 명령을 사용해야 하지만, C shell에서는 numeric 변수와 numerical expression이 제공됩니다. 뒤에 자세히 나옵니다. setenv는 Bourne shell에서 변수를 선언하고, export하는 작업을 한 번에 할 수 있도록 해 줍니다.
변수(2) 스트링 변수의 배열 % set colors = (red green blue orange yellow) % echo $colors[3] blue % echo $colors[2-4] green blue orange 배열을 선언할 때에, 배열의 크기가 정해집니다. 즉, 한 번 선언하면 크기를 바꿀 수 없습니다. 배열의 첫번째 원소는 1, 두번째는 2… 등의 첨자를 사용합니다. 선언할 때에 원소의 값을 모르면, null string( ‘ ‘)으로 정의할 수 있습니다.
변수(3) 수치 변수 사용법 : @ var-name op expr 연산자 op에 대해서는 교과서 표 참조 % @ count = 0 % @ count = (5 + 2) % @ result = ($count < 5) % @ count += 5 % @ count++ @와 count은 붙어 있으면 안됩니다. 왜냐면, @count를 하나의 명령어로 인식하기 때문입니다. 연산자는 C language와 유사합니다. 단, 연산자와 상수, 변수 등은 붙어 있으면 안됩니다(괄호는 예외). 변수의 값을 표시할 때는, echo $count와 같이 합니다. 논리 연산자(>, <,…)에 대해서, 참일 때는 1, 거짓이면 0의 값을 갖습니다. 위의 예에서, @ count=0 --> count = 0 @ count=(5 + 2) --> count = 7 @ result=($count < 5) --> result=0 @ count += 5 --> count=12 @ count++ --> count=13
변수(4) 수치 변수의 배열 사용법 : @ var-name[index] op expr % set ages = (0 0 0 0 0) % @ ages[2] = 15 % @ ages[3] = ($ages[2] + 4) % echo $ages[3] 19 수치 변수의 배열을 선언할 때는 @가 아니라 set을 사용합니다. 마찬가지로, 배열의 크기는 선언할 때에 정해집니다. 값을 모를 때는 null( ‘ ‘)로 정의 할 수 있습니다. 즉, set ages=(0 1 ‘ ‘)
변수(5) 특수한 형태의 사용자 변수 $# - 배열의 원소의 개수 $? - 변수의 선언 여부 % set days = (mon tues wed thurs fri) % echo $#days ; number of array elements 5 % echo $?days ; if variable days is declared 1 ; true (0 = false) $# - 은 변수의 원소의 개수입니다. 배열이 비어 있으면 $#days=0 입니다. 배열이 아닌 변수(앞에 앞 장의 count)는 $#count=1 입니다. 배열이 null로 초기화되어 있어도, 개수에 포함됩니다. 즉, set days=(‘ ‘ ‘ ‘) 이어도, $#days=2 입니다. $? - 은 변수가 선언되어 있으면 1, 선언되어 있지 않으면 0 입니다.
쉘 변수(1) 보통 C shell의 스타트업 파일인 .login이나 .cshrc에서 정의됨 임의의 값을 취하는 변수 $argv 쉘의 명령어 인자를 저장. argv[0], argv[1] 등 $#argv argv의 요소의 개수 $cdpath cd 명령시 파일 이름을 탐색하는 경로를 지정 set cdpath = (/home/jenny /home/jenny/letters) $cwd 작업 디렉토리의 이름을 지정 $history history의트기 $HOME 홈 디렉토리의 경로명 C shell의 쉘변수에는 임의의 값을 취하는 변수와 on/off 스위치로 사용되는 변수가 있습니다. 각 쉘변수의 자세한 내용은 교재를 보라고 합시다. cdpath - Bourne shell에서와 똑같습니다. cwd - 시험에 나왔었죠. pwd는 실제 디렉토리를 보여 주는 명령어이고, cwd는 심볼릭 링크를 따라서 지정되는 쉘변수 입니다. HOME - C shell에서는 cd 명령의 홈디렉토리뿐만 아니라, ~의 기능에도 관계합니다. 현재 shell에서 HOME을 바꿔도 영향을 미치지는 않습니다, 왜냐면, 메모리에 기억되는 값은 쉘이 처음 시작할 때의 환경변수이기 때문이죠. 그러나, setenv HOME /tmp 라고 하고, 새로운 쉘을 시작하면, 그 쉘에서는 영향을 받습니다. 즉, cd 라고 하면, /tmp로 이동하고, ~가 /tmp로 대치되죠.
쉘 변수(2) $PATH 명령어 탐색시 사용되는 디렉토리들의 경로명 setenv PATH (/usr/bin /usr/ucb /bin ~/bin . ) $prompt 프롬프트의 지정(Bourne shell에서의 PS1) 보통 .cshrc 파일에 다음과 같이 set prompt = ‘ ! % ‘ $savehist 로그아웃시 history 리스트로부터 기억되는 명령어의 개수 (홈 디렉토리의 .history)에 기억됨 $shell 쉘의 경로명 $status 지난번 명령어 실행시 return되 exit 상태 기억 $$ 현재 쉘의 PID 번호 저장 PATH - setenv 와 set 의 사용법이 다른 것에 유의합시다. 위의 예에서는 nonnumeric string array로 선언되었습니다. prompt - ! 는 event 번호입니다. history에서 사용하는.. 즉 위의 예를 따르면 프롬프트가 다음과 같이 바뀝니다. 12 % cd 13 % vi …. savehist - 보통 로그아웃하면 history list는 모두 지워집니다. 하지만 다음 번 로그인할 때까지, 이전의 history를 유지하고 싶을 때 사용합니다.
쉘 변수(3) on/off 스위치로 사용되는 변수 $echo 명령어 수행 전에 그 명령어를 화면에 보여 줌 $filec file name completion을 사용함. <ESC> 또는 ^D 의 기능 확장. $ignoreeof 쉘로부터 exit하는 방법의 지정 ^D로 쉘을 종료할 수 없음 $noclobber 출력의 재지정(>, >>) 시, overwrite 방지 기능 >!, >>! 으로 무시할 수 있다. $noglob ambiguous filename의 확장 금지 ?, *, [ ] 를 일반문자로 인식 $notify background 작업 수행 상태의 변화를 알림 filec - 앞에도 나왔었지만, set 되어 있으면, filename completion을 합니다. ignoreeof - set 되어 있으면, ^D를 사용해서 쉘 종료 불가능 noclobber - 교재에 설명이 있습니다. 생각과는 다를 수 있으니, 교재를 읽어 보라고 합시다. noglob - set 되어 있으면, ?, *, [, ] 등을 해석하지 않고 일반 문자로 취급 notify - background job의 상태가 변하면(running, done, stop..) 즉시 알림 명령어의 첫글자가 ^D이면, file name completion을 하지 않고, 쉘을 종료합니다. 그러나, ^D가 첫글자가 아니면 file name completion을 합니다.
C shell script(1) 쉘 스크립트 실행 방법 자동적으로 수행되는 쉘 스크립트 스크립트의 첫 줄에 사용될 쉘을 명시 #!/usr/bin/csh 쉘의 호출시 사용할 쉘의 이름을 명시 % csh reminder 자동적으로 수행되는 쉘 스크립트 .login, .cshrc, .logout 모두 사용자의 홈 디렉토리에 존재 Bourne shell 에서 설명이 나왔었죠. #!/usr/bin/csh 라고 하면, OS 가 스크립트를 수행할 쉘을 선택해 줍니다. % csh script-name 이라고 하면 무조건 C shell 이 스크립트를 수행합니다. 기본적으로 쉘을 지정하지 않으면, Bourne shell이 스크립트를 수행하게 되어 있습니다. 따라서 C shell script는 위의 방법으로 실행해야 합니다. #!/usr/bin/csh 를 사용하려면, 당연히 chmod +x를 해야 겠죠.
C shell script(2) .login .logout 로그인 시 수행. 환경변수, 터미널 타입 등의 지정 setenv TERM vt100 stty erase ‘^X’ kill ‘^U’ echo “This is who’s on the machine:” who .logout 로그아웃 시 수행 echo Remember to turn on call echo forwarding before you go home. sleep 10 .login - 로그인~로그아웃 동안에 변하지 않는 값들을 지정합니다. 로그인할 때에 한 번 수행할 일들을 지정합니다. setenv TERM vt100 - TERM이라는 환경변수값 설정 stty erase ‘^X’ - backspace key 지정. 보통 stty erase ^H 라고 하죠. stty kill ‘^U’ - line kill key 지정. .logout - 로그아웃할 때에 수행할 일들을 지정. 위의 예에서는 메시지를 2개 출력하고, 10초 동안 있다가 종료.
C shell script(3) .cshrc 새로운 C shell 호출 때마다 수행됨. 특정 쉘에 국한된 변수와 파라미터 값의 지정 set noclobber set ignoreeof set history = 100 set prompt = ‘ ! % ‘ set PATH = (/usr/bin /usr/ucb /usr/sbin ~/bin) alias h history alias dir ls -l .cshrc - 새로운 shell 호출 때마다 수행됩니다. 따라서 C shell script를 수행할 때도 .cshrc를 먼저 수행합니다.
제어 구조(1) if (expression) simple-command if ($#argv == 0) echo “if_1: there are no arguments” 파일의 상태를 검사하는 expression (예, -d /usr/bin ) d 디렉토리 파일인지 검사 e 파일의 존재여부 검사 f 보통 파일인지 검사 o 사용자가 파일의 소유자인지 검사 r 읽기 권한 여부 w 쓰기 권한 여부 x 실행 권한 여부 z 파일의 길이가 0바이트인지 검사 모두 한 줄에 다 써야 합니다. simple-command - 하나의 명령만 가능. pipe도 쓸 수 없습니다. 여러 개의 명령을 쓸려면 if-then 구문을 사용해야 함. expression - 앞에서 배운 Logical expression을 사용할 수 있습니다. 특별히 파일의 상태를 검사하는 expression 제공 파일이 없거나 접근할 수 없으면 0, 검사 결과가 true 이면 1, false이면 0 입니다.
제어 구조(2) Goto if ($#argv == 2) goto goodargs echo “Usage: goto_1 arg1 arg2” exit 1 goodargs: ….
인터럽트의 처리 onintr 인터럽트가 발생하면 프로그램의 제어를 옮김 onintr close while ( 1 == 1 ) echo Program is running. sleep 2 end close: rm -f /tmp/$$* echo End of program 사용자가 Interrupt key(보통 ^C 또는 DEL)를 눌렀을 때 발생합니다. 위의 예에서는 임시 파일을 삭제하고 종료합니다.
If Then Else 예 set number = $argv[1] if ($number < 0) then @ class = 0 else if (0 <= $number && $number < 100) then @ class = 1 else if (100 <= $number && $number < 200) then @ class = 2 else @ class = 3 endif echo The number is in class $class. 여러 개의 명령어를 사용할 수 있는 if 구문입니다. 물론, else, else if 도 제공됩니다. 앞의 if 구문과의 차이점은 then~endif, then~else, else if ~ endif 를 사용해서 여러 개의 명령어를 묶을 수 있다는 거죠. set number = $argv[1] 은 @ number = $argv[1] 라고 해도 됩니다. 왜냐하면, 변수들은 실제적으로는 모두 문자열로 취급하기 때문에 nonnumeric string variable과 numeric variable은 사실상의 구분이 없기 때문입니다. 하지만 산술 연산과 @ 명령에서는 구분을 합니다. 예를 들어, set number = 1은 가능하지만, @ number = string은 불가능합니다. set number = ( 1 + 1) 은 1, +, 1 을 원소로 갖는 배열이 되고, @ number = ( 1 + 1) 은 2를 갖는 변수가 됩니다.
Foreach, Break, Continue if ($#argv != 2) goto usage foreach i ( *$1* ) mv $i ` echo $i | sed -n s/$1/$2/p` end else usage: echo "Usage: rename arg1 arg2" exit 1 endif break : end문 다음으로 제어가 이동됨 continue : end문으로 제어가 이전됨 foreach index (apple banana grape) echo $index end Bourne shell의 for 구문과 마찬가지로 임의의 list에 있는 원소에 대해 루프를 돕니다. 즉, 바로 위의 예에서는 다음과 같이 출력이 됩니다. apple banana grape TP에 있는 예는 현재 디렉토리에 있는 파일이름의 일부를 바꾸는 프로그램입니다. 예를 들어, my_memo.0911를 my_letter.0911로 바꿉니다. $1, $2 - $argv[1], $argv[2]를 줄여 쓴 것입니다. Bourne shell과 같음. *$1* - 현재 디렉토리에서 매치되는 파일 이름. 예를 들어, 첫번째 인수가 zz 이면, 현재 디렉토리에서 중간에 zz가 들어가는 파일들의 이름으로 리스트가 만들어 집니다. list에 regular expression을 쓸 수 있습니다. sed -n s/$1/$2/p - 표준 입력으로 들어온 스트링에서 $1을 $2로 바꾼다. -n은 표준 입력을 표준 출력으로 복사하지 말라는 옵션. /p 는 매치가 될 때 출력하라는 플랙.
While 예 # sum the numbers between 1 and n set limit = $argv[1] set index = 1 set sum = 0 while ($index <= $limit) @ sum += $index @ index++ end echo The sum is $sum
Switch if ($#argv == 0) then echo "Usage: switch_1 [yes|no]" exit 1 else switch ($argv[1]) case [yY][eE][sS]: echo Argument one is yes. breaksw case [nN][oO]: echo Argument one is no. default: echo Argument one is neither yes nor no. endsw endif Bourne shell의 case 구문과 같은 기능입니다. case pattern:… 에 사용하는 pattern에서도 Bourne shell에서처럼 특수 문자들이 있구요. 특히, pattern matching을 한다는 것만 빼면 C language의 switch문과 거의 유사하군요. 위의 예는 명령행 인수를 yes일 때, no 일때, 그 밖에 다른 문자열 일때로 branch 하는 군요.
Bourne shell script 과제 - 구구단 예 : $ mt 3-9 3단부터 9단까지를 표준출력으로 출력한다. 제약 명령행 인수가 위의 형식에 맞지 않거나, 명령행 인수가 없거나, lower가 upper보다 크면 사용법을 출력하고 종료. Usage: mt lower-upper 프로그램내에 최소한 하나 이상의 함수를 사용한다. 참고 test. awk, grep의 사용법 제출 프로그램 설명과 실행 결과를 hard copy로 체출 Shell script도 디스켓 또는 E-mail로 제출 기한 : 1주 후