본문 바로가기

Academy I/Tech Academy

Unix 14 Shell Programming의 추가사항

Shell Programming의 추가사항 : getopts

대부분의 유닉스 명령어들은 명령어의 기본적인 출력 형식의 변형을 얻을수
있도록 하기위해 몇가지 옵션들을 제공한다. 사용자들은 이 옵션을 사용하여
보다 자신의 작업 목적에 맞는 형식으로, 명령어의 출력을 얻을 수 있게된다.
물론 사용자가 작성한 쉘 프로그램에서도 옵션을 입력받아 처리할 수 있다.
또한 명령어 라인상에 지정된 쉘 프로그램의 인자와 옵션및 옵션에 대한 인자들을
구별하여 처리하도록 제어를 행할 수 있다. 이들 제어는 getopts 명령어를
사용하여 수행한다.

getopts 명령어를 사용하여 옵션및 옵션 인자를 처리하기 위한 형식은다음과 같다.

┌─────────────────┐
│  while getopts opts name         │
│  do                              │
│       case $name in              │
│            opt1).                │
│                 .                │
│                 ;;               │
│            optN).                │
│                 .                │
│                 ;;               │
│               *)echo $USAGE      │
│                 exit 2;;         │
│       esac                       │
│  done                            │
│  shift `expr $OPTIND - 1`        │
└─────────────────┘

이 예에서 opts는 명령어에 유효한 옵션을 의미한다. 이때 인자가 수반되는
옵션들에 대해서는 옵션문자의 뒤에 :을 지정한다. 이들 처리되는 옵션 인자들은
변수 OPTARG에 할당되고, 그리고 처리된 옵션및 옵션 인자의 갯수가 OPTIND
변수에 할당된다. 실행시에, 만일 opts 부분에 선언되어 있지 않은 옵션이
주어지면, 변수 USAGE가 getopts 명령어에 의해서 표시된다.

name은 while 루프가 매번 수행될 때마다, 명령어 라인상에 지정된 옵션이
저장되는 변수의 이름이다. while 루프는 각각의 인자들에 대해 한번씩 실행된다.

while 루프내에서, 각각의 인자들은 지정된바에 따라서 변수를 할당하거나,
옵션이 지시하는 다른 명령어를 실행하는 것으로 처리된다. 옵션의 인자들은
이후에 다시 사용하려면 다른 변수에 저장하여야 한다. 그리고 while 루프에서
모든 옵션 인자들을 처리한 후에, 아직 처리되지 않은 명령어 라인 인자들을
(옵션과 옵션 인자들을 제외한 나머지 인자들) 처리하기 위해서 shift를 행한다.
shift 한후, 포지셔널 파라메터 $1에는 아직 처리되지 않은 첫번째 명령어 라인
인자가 설정된다.

┌───────────────────────────────────┐
│geto                                                                  │
├───────────────────────────────────┤
│USAGE='Usage: geto [-s] -h formalname] -g nickname] car [car...]'     │
│#         USAGE 변수는 geto 프로그램 기동시 부적합한 옵션을 지정했을때│
│#         표시할 메세지를 정의한 변수이다.                            │
│while getopts h:g:s o                                                 │
│#         getopts 명령에 두개의 인자가 지정되어 있다. 첫째는          │
│#         프로그램에 유효한 옵션을 정의하기 위한 인자이고, 두번째     │
│#         인자는 명령어 라인상에 지정된,  -로 구별되는 옵션들이       │
│#         순차적으로 설정되는 변수이다. 이 변수는 while 루프 제어문의 │
│#         매번 루프시에 case문에 의해 처리된다.                       │
│do                                                                    │
│      case $o in                                                      │
│           h)formal=$OPTARG; echo HELLO $formal ;;                    │
│#         여기서 눈여겨 볼것이 있다. OPTARG 변수에는 현재의 루프에서  │
│#         처리되고 있는 옵션의 인자가 설정되는데, 현재 처리되고 있는  │
│#         옵션의 인자는, 현재의 루프에서만 OPTARG 변수에 유지된다.    │
│#         이 옵션 인자를 다시 참조하기 위해서는, 이 예와같이 다른     │
│#         변수에 저장해 두어야한다.                                   │
│           g)aka=$OPTARG; echo GOOD BYE $aka ;;                       │
│           s)echo you are working on `uname` ;;                       │
│           *)echo $USAGE ;; exit 3 ;;                                 │
│#         이 부분에서, 명령어 라인상에 유효하지 않은 옵션이 처리된다. │
│#         이로인해 잘못된 옵션 지정시, 오류 메세지가 표준에러(stderr) │
│#         가 아닌 표준출력(stdout)으로 처리된다.                      │
│      esac                                                            │
│done 2> /dev/null                                                     │
│#         2>는 표준에러(stderr)의 출력을 null 화일로 처리하기 위한    │
│#         지정이다. 이 지정에 의해 쉘에 의해 돌려지는 표준에러        │
│#         메세지는 화면상에 표시되지 않는다.                          │
│echo before the shift there were $# arguments                         │
│#         $#은 프로그램 실행을 요구한 명령어 라인상에 지정된 인자의   │
│#         총 갯수가 설정된다.                                         │
│shift `expr $OPTIND - 1`                                              │
│#         OPTIND 변수에는 처리된 옵션및 옵션 인자의 갯수가 저장된다.  │
│#         shift가 수행되면, 명령어 라인상에서 처리되지 않은 인자들만이│
│#         명령어 라인 인자로 남게된다.                                │
│echo after the shift there are $# arguments                           │
│#         shift한후 인자의 갯수를 표시한다.                           │
│if [ $# -lt 1 ]                                                       │
│#         인자의 갯수가 1보다 적은 경우에는 명령어 라인상에           │
│#         명령어 라인 인자가 하나도 지정되지 않았음을 의미한다.       │
│then                                                                  │
│   echo $USAGE; echo "argument expected";exit 2                       │
│#         명령어 라인 인자를 지정하지 않았다는 오류 메세지를 표시한후,│
│#         프로그램이 종료된다.                                        │
│fi                                                                    │
│if test -n "$formal" -a -n "$aka"                                     │
│#         옵션 인자를 필요로 하는 옵션에 인자를 지정했는가를 검사한다.│
│then                                                                  │
│    echo $formal is also known as $aka                                │
│#         옵션 인자들에 대한 처리를 행하고 있다.                      │
│fi                                                                    │
│echo "$1 was entered as your dream car"                               │
│#         명령어 라인 인자를 화면상에 표시하기 위한 지정이다.         │
│if [ $# -gt 1 ]                                                       │
│#         명령어 라인상에 아직 처리되지 않은 인자가 있는가를 검사한다.│
│then                                                                  │
│shift                                                                 │
│echo "you also wouldn't mind being seen in any of the following:$*"   │
│fi                                                                    │
│exit 0                                                                │
│#         프로그램이 정상 종료된다.                                   │
└───────────────────────────────────┘

KORN>geto -sh nicholas -g nick jaguar masarstl lamborginl
you are working on bbp6k50a
HELLO nicholas
GOOD BYE nick
before the shift there were 7 arguments
after the shift there are 3 arguments
nicholas is also known as nick
jaguar was entered as your dream car
you also wouldn't mind being seen in any of the following: masarati lamborgini

위의 예제를 실행했을때, 위와같은 결과가 나오게 되는 과정은 독자 스스로 한번
분석해 보기를 바란다.


---------------------------------------------------------------------------



Shell Programming의 추가사항 : wait,line

1) wait 명령어

    wait 명령어는 쉘 프로그램내에서 직전에 수행시킨 Backgound Job이
    종료될때까지, 쉘 프로그램의 실행을 정지할수 있는 기능을
    제공하는 명령어이다.

    다음은 wait 명령어의 사용예이다.

    ┌─────────────────────────┐
    │myprog                                            │
    ├─────────────────────────┤
    │echo first list                                   │
    │ls                                                │
    │cat f1 f2 f3 f4 f5 f6 f7 | tee final&   <-- Background Job을 실행.
    │wait                                <-- 직전의 Background Job이
    │rm f1 f2 f3 f4 f5 f6 f7                 끝날때까지 실행을 중지한다.
    │echo second list                                  │
    │ls                                                │
    └─────────────────────────┘

    $myprog
    first list
    f1  f2  f3  f4  f5  f6  f7    <-- ls 명령의 실행 결과로, 기존에 f1부터
    second list                       f7까지의 화일이 있음을 알수 있다.
    final                         <-- 이를 보고 Background 작업이 정상적으로
                                      수행된것을 알수 있다.

2. line 명령어

    line 명령어는 표준입력(stdin)으로부터 한 라인의 데이타를 받아들여,
    이 입력을 표준출력(stdout)에 위치시킨다. 어떻게 보면, line 명령어는
    read 명령어와 유사하나, line 명령어는 입출력 방향전환이 요구될때
    주로 사용된다.

    line 명령어는 화일로부터 한라인의 텍스트를 읽고, 변수에 그 라인을
    저장할때 아주 요긴하게 사용할수 있다. read 명령어를 사용할 경우에는
    입력에 대한 방향전환이 허용되지 않는다. 즉; 표준 입력에서만
    입력을 받을수 있다.

    다음은 read 명령어와 line 명령어를 비교하기 위한 예이다.

      ┌───────────┐
      │ $read storeline      │ read 명령어는 표준입력으로 한 라인의
      │ "Welcome to UNIX"    │ 데이타를 받아들여, 그를 지정한 변수에
      │ $echo $storeline     │ 저장한다.
      │ "Welcome to UNIX"    │
      ├───────────┤
      │ $storeline=`line`    │ line 명령어는 표준입력으로 한 라인의
      │ "Welcome to UNIX"    │ 데이타를 받아들여, 그를 표준출력으로
      │ $echo $storeline     │ 보내는데, 이 예에서는 그 표준출력이
      │ Welcome to UNIX      │ 변수에 저장된다.
      └───────────┘

    ┌─────────────────────────────────┐
    │lines                                                             │
    ├─────────────────────────────────┤
    │c=`wc -l names | cut -c1 -8`                                      │
    │# names 화일의 라인수가 c 변수에 저장된다.                        │
    │i=1                                                               │
    │# 루프의 반복 횟수를 계산하기 위한 변수의 초기값을 1로 설정       │
    │while [ $i -le $c ]                                               │
    │# 루프를 names 화일의 라인수만큼만 수행하기 위한 지정이다.        │
    │do                                                                │
    │  eval store$i='`tail +$i names | line`'                          │
    │# name 화일의 i번째 라인을 읽어, 그 라인을 store$i 변수에 저장.   │
    │# 지정된 store$i 변수의 $i는 루프의 반복횟수로 대치된다.          │
    │  i=`expr $i + 1`                                                 │
    │# 루프의 반복 횟수가 설정된 변수의 값을 1 증가시킨다.             │
    │done                                                              │
    │# 루프가 종료하면,names 화일의 각 라인이 변수에 각각 저장된다.    │
    │i=`expr $c`                                                       │
    │# 루프 반복 횟수를 i 변수에 저장한다. 이때의 반복 횟수는          │
    │# names 화일의 총 라인수가 된다.                                  │
    │while [ $i -ge 0 ]                                                │
    │do                                                                │
    │  eval echo $"store$i"                                            │
    │  i=`expr $i - 1`                                                 │
    │# 각각의 변수에 저장된 내용을 화면에 표시하는 지정인데,           │
    │# 이전의 while 루프와는 반대로 가장 마지막 변수에 저장된          │
    │# 내용이 먼저 출력된다.                                           │
    │done                                                              │
    └─────────────────────────────────┘

    $cat names
    Robert Ludlum Philadelphia
    Agatha Christie London
    Bradford Taylor Atlanta
    Jeffery Archer Seattle
    Tom Clancy Washington

    $lines                             <--- lines 프로그램의 지정에따라,
    Tom Clancy Washington                   본래 저장되어 있는 순서와
    Jeffery Archer Seattle                  반대로 출력이 수행된다.
    Bradford Taylor Atlanta
    Agatha Christie London
    Robert Ludlum Philadelphia


---------------------------------------------------------------------------



Shell Programming의 추가사항 : |&

1) Korn Shell의 Co-processing

    line 명령어는 화일내의 라인을 데이타로 변수내에 읽어들이기 위해 유용하게
    사용할수 있다. 그러나 line 명령어를 사용할 경우에, 특정 화일내의 모든
    라인을 처리하기 위해서는 이전 강의에서 소개한 예제처럼 루프 제어문과 같은
    복잡한 제어문을 사용하여 프로그램을 작성해야 한다.

    이런 경우에 Korn Shell에서 제공하는 Co-processing 기능을 이용한다.
    Korn Shell은 두개의 프로세스간에 상대 프로세스와 통신할수 있도록 해주는
    Co-processing 기능을 제공한다. 사용자는 Co-processing 기능을 사용함으로써
    첫번째 프로세스로 부터의 라인단위의 출력을 순차적으로 두번째 프로세스로의
    라인단위 입력으로 처리할수 있다.

    Co-processing을 사용하기 위해서는, 다음과 같이 첫번째 프로세스에 뒤이어
    |& 심볼을 지정한다.

         first_process |& second_process
         ( first,second_process가 실행시 Co-processing 되어진다.)

    위의 형식에서 프로세스 지정시
    표준입력으로 부터 라인을 읽기 위해서는 read -p 명령어를 사용하고,
    라인을 표준 출력에 저장하기 위해서는 print -p 명령어를 사용한다.

    다음은 Co-processing 기능을 사용한 사용예이다.

    ┌──────────────────────────────┐
    │coproc  # Korn shell의 Coprocessing ##                      │
    ├──────────────────────────────┤
    │cat names |&          # cat 명령어의 실행 결과가 라인 단위로│
    │while true            # 순차적으로 후속된 while 명령어의    │
    │do                    # 표준 입력으로 처리된다.             │
    │                      # 즉, 두 프로세스가 공조하여 처리된다.│
    │  read -p first last town                                   │
    │                      # 표준입력으로부터 라인을 읽어들인다. │
    │  if [ $? -ne 0 ] ; then exit 0 ; fi                        │
    │  echo $last $first $town >> authors                        │
    │done                                                        │
    └──────────────────────────────┘

    KORN> cat names
    Robert Ludium Philadelphia
    Agatha Christie London
    Bradford Taylor Atlanta
    Jeffery Archer Seattle
    Tom Clancy Washington

    KORN> coproc

    KORN> cat authors                  # 위에서 확인한 names 화일의 내용이
    Ludlum Robert Philadelphia         # 위의 프로그램 실행에 의해 순서가
    Christie Agatha London             # 바뀌어 출력되고 있다.
    Taylor Bradford Atlanta
    Archer Jeffery Seattle
    Clancy Tom Washington


---------------------------------------------------------------------------


Shell Programming의 추가사항 : exec

1) File Descriptor(화일 기술자)

    쉘 프로그램에서 특정 화일을 사용할 경우, 사용할 화일을 사전에
    화일 기술자 테이블(File Descritor Table)상에 하나의 엔트리(entry)로
    등록한후, 화일명을 대신하여 화일 기술자 테이블의 엔트리 식별자를 이용,
    화일을 참조할 수 있다. 이들 엔트리 식별자들을 화일 기술자라 한다.
    각각의 화일 기술자들은 0,1,2,3등의 숫자로 식별된다.

    그런데 프로그램 실행시에 꼭 필요로 하는 표준입력, 표준출력 그리고
    표준에러를 처리하기 위한 화일들은 쉘에 의해서 자동적으로
    화일 기술자 0, 1, 2로 할당되어 있기 때문에, 사용자는 이들 화일에 대해
    별도로 등록 작업을 수행하지 않고도 사용 가능하다.
    다음은 쉘에 의해 자동적으로 할당되는 화일 기술자및 사용예를 보여준다.

    ┌──────┬────────┬───────────────┐
    │화일 기술자 │ 의미           │사용예                        │
    ├──────┼────────┼───────────────┤
    │     0      │ 표준입력       │0<,0<<,<,<<                   │
    ├──────┼────────┼───────────────┤
    │     1      │ 표준출력       │1>,1>>,>,>>                   │
    ├──────┼────────┼───────────────┤
    │     2      │ 표준에러       │2>,2>>                        │
    └──────┴────────┴───────────────┘

    ( 참고로 유닉스에서는 모니터, 키보드, 프린터등 모든 시스템 주변장치들을
    하나의 화일로 취급한다. 이들에 대한 자세한 사항은 차후에 강의될
    유닉스 관리자 과정에서 자세히 소개한다. )

    사용자는 쉘 프로그램에서 추가의 화일들을 화일 기술자 테이블상에
 (FDT) 등록하여 사용할 수가 있다. 이 경우 사용자는 3에서 20까지의
    화일 지시자를 exec 명령어를 이용하여, 각각의 화일에 대응시킬수 있다.
    이럼으로써 사용자는 쉘 프로그램에서 특정 화일의 화일명을 지정하여
    사용하는 대신에, 그에 상응하는 화일 기술자 번호를 이용하여 화일을
    억세스할 수 있게 된다.

    뿐만아니라 화일 기술자 지정과 함께 & 심볼을 이용함으로써 대상화일들을
    연결(link)하여 작업하도록 지정할 수 있다.
    예를들면 다음과 같다.

         $cat fileA fileB nofile> allfile 2>&1

    이 경우 표준에러를 표준출력에 연결(link)한다.
    즉, nofile로 인한 에러 메세지가, 표준출력 화일로 설정된 allfile이라는
    화일에 표준출력 내용과 함께 저장된다.

    다음은 화일 기술자를 이용한 작업 화일의 사용예를 보여준다.

    $command < filename
    $command 0< filename     ┌────┐        ┌──┐
                             │Command ├< ───┤File│ 표준입력의
                             └────┘  stdin │    │ 방향전환
                                                 └──┘
    $command > filename
    $command 1> filename     ┌────┐        ┌──┐
                             │Command ├────> File│ 표준출력의
                             └────┘  stdout│    │ 방향전환
                                                 └──┘

    $command 2> filename     ┌────┐        ┌──┐
                             │Command ├────> File│ 표준에러의
                             └────┘  stderr│    │ 방향전환
                                                 └──┘

    $command > filename 2>&1 ┌────┐        ┌──┐
                             │Command ├────> File│ 표준출력및
                             └────┘  stderr│    │ 표준에러의
                                           stdout└──┘ 연결(link)

    ( 즉, 표준에러의 출력 내용을 표준출력으로 지정한 화일에 함께 저장한다. )

2) 화일 기술자를 지정한 exec 명령어

    이미 설명한대로 exec 명령어는 현재의 쉘내에서 프로그램을 실행하기 위해서
    사용한다. 그외에도 exec는 화일 기술자를 확립하기 위해서도 사용한다.

    exec 명령어를 사용하여 화일을 특정 화일 기술자로 확립함으로써,
    표준입력 또는 표준출력을 동적으로 방향전환(Redirect)할수 있다.

    <&-와 >&-를 사용하여, open된 화일을 close할 수 있다.

    다음은 화일 기술자를 사용하는 예제를 보여준다.

    ┌──────────────────────────────────┐
    │myprog                                                              │
    ├──────────────────────────────────┤
    │exec 3>myout           # 3번 화일 기술자로 myout 화일을 출력용으로  │
    │                         할당한다.                                  │
    │exec 4&3                                    │
    │                       # 위 출력은 myout 화일에 저장된다.           │
    │echo This should go to the terminal                                 │
    │                       # 위 출력은 표준출력 처리된다.               │
    │cat <&4                                                             │
    │                       # cat의 입력은 4번 화일 기술자로 등록된      │
    │                       # myfile의 내용이 된다.                      │
    │echo Later we add this line to the end of the file >&4              │
    │                       # 출력이 myout 화일에 추가된다.              │
    │3>&-                                                                │
    └──────────────────────────────────┘

    $myprog
    This should go to the terminal
    This should go to myout
    $cat myout
    This should go to myout
    Later we add this line to the end of the file

---------------------------------------------------------------------------



Shell Programming의 추가사항 : Inline

1) Inline 입력 방향전환

    Inline 입력 방향전환의 형식은 다음과 같다.

         command <<match

    Inline 입력 방향전환은 라인의 처음에 match라는 문자열이 지정되어
    있는 라인을 만날때까지 후속되는 라인을 표준입력으로 사용하도록 쉘에게
    지시한다.

    <<- 형식으로 지정함으로써 라인의(end-of-input 문자열을 갖은 라인 포함)
    처음에 위치하고 있는 탭(Tap)을 없애도록 지시할수도 있다.

    이러한 Inline 입력 기능은 쉘 프로그램에서 곧장 명령어의 표준입력을
    지정하기 위해서 주로 사용된다.

    이 기능은 통상 HERE 다큐멘트 기능이라 불리운다.

    다음은 쉘 프롬프트상에서 Inline 입력 기능을 사용하는 예이다.

    $wc -l <<THATSALL      # 후속되는 명령어 라인상에 첫 문자열이
    >Line 1                # THATSALL일 때까지의 후속 라인들을
    >Line 2                # 표준입력 처리한다.
    >THATSALL              # (wc -l 명령어는 라인수를 계산하는 명령)
    2
    $

    다음은 쉘 프로그램에서 Inline 입력 기능을 사용하는 예제이다.

    ┌─────────────────────────────────┐
    │myprog                                                            │
    ├─────────────────────────────────┤
    │while read n1 n2          # 숫자 두개를 입력받아 루프를 수행한다. │
    │do                                                                │
    │  echo `expr $n1 + $n2`   # 입력받은 두 숫자를 더한다.            │
    │done <<END                # <<END 지정으로 인해 read 명령어의     │
    │3 4                       # 표준입력은 라인의 처음에 END가 지정된 │
    │5 6                       # 라인까지의 후속 라인으로 방향전환된다.│
    │7 8                                                               │
    │END                                                               │
    └─────────────────────────────────┘

    $myprog
    7
    11
    15

2. Inline 입력 방향전환의 응용

    Inline 입력 기능은 특정 명령어에서 처리할 입력 데이타를 제공하는
    경우 이외에도, 특정 명령어에서 필요로하는 명령어의 지시어(Directive)를
    제공할 수도 있다. 이 기능을 사용함으로써 쉘 프로그램내에서
    다음과 같이 ed와 같은 라인 편집기등을 사용할 수 있게된다.

    ┌─────────────────────────────────┐
    │update                                                            │
    ├─────────────────────────────────┤
    │today=`date`                                                      │
    │ed $1 << STOP # $1은 사용자가 프로그램 실행시 제공하는 첫번째 인자│
    │1d            # ─┐                                              │
    │i             #   │이 부분은 Inline 입력 방향전환되어 ed 편집기에│
    │$today        #   │제공되는, ed 편집기의 명령어로 처리된다.      │
    │.             #   │                                              │
    │w             #   │                                              │
    │q             # ─┘                                              │
    │STOP                                                              │
    │echo "Update complete"                                            │
    └─────────────────────────────────┘
    $cat test        # 프로그램에서 편집하기 이전 상태의 화일을 보여준다.
    Friday Oct 29 12:34:55 CDT 1988
    This is a sample file used
    to display how the above here
    document work.
    $update test     # test라는 화일명이 프로그램내에서 $1으로 처리된다.
    106
    99
    Update complete
    $cat test       # 프로그램 실행후, 편집된 내용을 확인하고 있다.
    Tue May 8 13:58:00 CDT 1990
    This is a sample file used
    to display how the above here
    document works.


---------------------------------------------------------------------------



Shell Programming의 추가사항 : function & return

1) Shell functions

    하나의 작업을 수행하기 위해 필요한 일련의 명령어와 프로그램들을
    실행시마다 명령어 하나씩을 지정하는식으로 작업을 수행하면, 작업이
    상당히 번거로워질 것이다. 이런 경우 실행할 일련의 명령어들을
    쉘 프로그램으로 작성해서 수행하면 작업이 상당히 용이할 것이다.

    그렇다고 쉘 프로그램으로 작성해서 운용하는 것이 무조건 효율적이라고
    말할 수 없다. 왜냐하면, 쉘 프로그램은 디스크상에 존재하기때문에
    실행 요구시, 메모리로 로드해서 수행해야 한다는 부하가 예상되기
    때문이다. 물론 빈번히 수행되는 프로그램이 아닐 경우에는 이 정도의
    부하는 무시해도 상관없을 것이다.

    그러나 아주 빈번히 사용되는 프로그램의 경우에는 이를 제어할 필요가 있다.
    이런 경우와 같은 부하를 줄일수 있도록 제공하는 쉘의 기능이
    "Shell functions"이다.

    Shell functions은 사용자가 필요시에 정의하여 사용할 수 있으며,
    정의된 Shell functions은 메모리상에 보존됨으로써, 실행 요구시
    디스크로부터의 로드로 인한 부하없이 프로그램을 실행할 수 있게
    해준다.

    다음은 Shell functions을 정의하는 방식을 보여준다.

         ┌──────────────────────┐
         │name() { command; ...; command }            │
         └──────────────────────┘

         ┌──────────────────────┐
         │name() {                                    │
         │        command;                            │
         │        ...                                 │
         │        command;                            │
         │        }                                   │
         └──────────────────────┘

    위 형식에서 name은 Shell functions의 이름이며, 한쌍의 둥근괄호는
    쉘에게 Shell functions의 선언임을 알려주는 키워드이다. 그리고
    후속되는 중괄호는 Shell functions 요구시 실행할 일련의 명령어들을
    지정하기 위한 형식이다. 이들 명령어들을 지정함에 있어서 $1,$2와 같은,
    명령어 라인 인자들로부터 입력을 처리할 수 있는 포지셔널 파라메터들을
    함께 지정할 수 있다.

    Shell functions을 실행하는 방식은, 반 명령어들을 실행하는 방식처럼
    간단히 Shell functions의 이름만을 지정하면 된다.

    한번 선언된 Shell functions은 사용자가 로그인하고 있는 동안에만
    그 효력을 유지한다. 따라서 매번 새롭게 로그인할때마다 Shell functions을
    정의해야만 하는데, 이런 경우에는 .profile 속에 Shell function을
    선언해둠으로써 자동적으로 Shell functions을 정의하도록 할수있다.

    다음은 Shell functions의 사용예이다.

    $start() { echo "Hi $1 "; pwd; ls *; }
    $start unix
    Hi unix
    /usr/acct/hpt
    file1
    file2
    file3
    $

2) Return 명령어

    Shell functions내에서 특정 조건을 만날 경우에, 그 Shell function을
    종료해야 할 경우가 있다. 이런 경우 이미 설명했던 exit 명령어를
    사용하여, Shell functions을 종료하도록 지정할 수 있다.
    그 예는 다음과 같다.

         ┌───────────────────────┐
         │myprog                                        │
         ├───────────────────────┤
         │prog() {                                      │
         │  if [ -f $1 ]                                │
         │  then                                        │
         │     echo $1                                  │
         │  else                                        │
         │     exit  # if 제어문의 판단 결과가 거짓이면 │
         │  fi       # 후속되는 라인의 명령어들은       │
         │  }        # 실행되지 않는다.                 │
         │prog $1                                       │
         │echo $?                                       │
         │echo done                                     │
         └───────────────────────┘

    그러나 주의할 것이 있다.
    Shell functions내에서 exit 명령어를 내리면, 쉘 프로그램 자체가 종료하기
    때문에 후속되는 명령어들은(위 예에서는 prog, echo가 이에 해당) 실행되지
    않는다.

    바로 이런경우 Shell functions만을 종료하고, 쉘 프로그램내에 기술되어
    있는 후속되는 명령어들은 계속 수행하도록 하기 위해서는 return 명령어를
    사용한다. return 명령어의 형식은 다음과 같다.

              ┌──────────┐
              │return N            │
              └──────────┘

    위 형식에서 N은 Shell functions의 종료상태를 나타내는 숫자이다.
    만일 N이 생략되면, Shell functions내에서 마지막으로 수행했던
    명령어의 종료상태가 가정된다.

    다음은 return 명령어의 사용예이다.

         ┌───────────────────────┐
         │myprog                                        │
         ├───────────────────────┤
         │prog() {                                      │
         │  if [ -f $1 ]                                │
         │  then                                        │
         │     echo $1                                  │
         │  else                                        │
         │     return # return 지정으로 인해, Shell     │
         │fi        # functions만을 종료하고, 후속된    │
         │  }         # 명령어들을 계속하여 수행한다.   │
         │prog $1                                       │
         │echo $?                                       │
         │echo done                                     │
         └───────────────────────┘

    $ls m*
    myout myprog
    $myprog myfile
    1              <---- Shell functions내의 if 문의 종료상태이다.
    done 이 예는 myfile이 존재하지 않기 때문에 거짓이다.
    $myprog myout
    myout
    0              <---- if문의 종료상태가 참이다.
    done                 (myout이 존재하는 화일이기 때문에)
    $


---------------------------------------------------------------------------



C Shell의 환경
--------------------------------------------------------------------

1) C Shell의 환경

    C Shell은 켈리포니아 버클리 대학의 Bill Joy에의해 개발되었다.

    C Shell은 시스템 분석가, 전문 사용자, 시스템 관리자들을 겨냥한
    다양한 기능으로 인해 매우 널리 사용되게 되었다. C Shell은
    Bourne Shell보다 다양한 단축형 명령어, 사용자 정의형 명령어,
    작업 제어 기능, 이전에 수행된 명령어 억세스 기능및 C 언어와
    유사 형식의 쉘 프로그래밍 언어등을 제공한다.

    C Shell의 단점으로는 기본 쉘인 Bourne Shell과 호환성이 적은 것과,
    Bourne Shell에 비해 수행속도가 느리다는 것이다.

    사용자가 C Shell을 기본쉘(Login-shell)로 사용하기 위해서는
    /etc/passwd 화일의 사용자 로그인 정보에서 기본쉘로 /bin/csh라
지정하면 된다.

2) C Shell의 특수 화일

    C Shell은 사용자 작업 환경을 설정하기 위해 다음과 같은 몇개의
    특수 화일을 이용한다.

          /etc/cprofile
          .login
          .cshrc
          .logout

    이들 화일에 대해서 살펴보면..

    /etc/cprofile은 사용자별로 할당되는 .cshrc 또는 .login 화일에 앞서
    실행된다. 이 화일은 시스템 차원의 전반적 사용자 환경을 설정하기 위해
    시스템 관리자에 의해 사용되는 화일이다. 이 화일은 Bourne/ Korn Shell의
    profile과 동일한 기능을 수행한다.

    .login 화일은 Bourne Shell의 .profile과 동일한 기능을 수행하는 화일로서,
    로그인시에 사용자 환경을 설정하기 위한 stty 설정치들을 설정하거나 또는
    명령어들을 실행하기 위해 사용된다.

    .cshrc 화일은 .login 화일을 실행하기 전에, 설정 화일(Setup file)로서
    실행되는 C Shell에서 유일한 화일이다. .cshrc 화일에는 쉘 환경을
    초기화하기 위해 실행해야할 명령어들을 지정한다. 디폴트에 의해 이 화일은
    Alias 정의와 프롬프트 변경 그리고 History list를 초기화하기 위해
    사용된다.

    .logout 화일은 사용자 로그아웃(logout) 직전에 실행해야할 명령어들을
    지정하기 위해 사용되는 화일이다. 이 화일은 로그아웃 이전에 사용자의
    작업정리 기능들이나 백업 기능들을 수행하도록 하기위한 목적으로 주로
    이용된다.

    다음은 이들 화일을 요약한 그림이다.

 ┌───────┐┌───────┐┌───────┐┌───────┐
 │              ││              ││              ││              │
 │/etc/cprofile ││$HOME/.cshrc  ││$HOME/.login  ││$HOME/.logout │
 │              ││              ││              ││              │
 └───────┘└───────┘└───────┘└───────┘
  System            User              User setup        User cleanup
  preparation       initialization                       or backup


---------------------------------------------------------------------------



C Shell의 변수
--------------------------------------------------------------------

1) set, unset, setenv, unsetenv

    C Shell 변수는 set 명령어를 사용하여 정의하는데, 그형식은 다음과 같다.

       ┌────────────────┐
       │set varname=string              │
       └────────────────┘

    C Shell에서 변수들의 참조는 Bourne Shell과 유사하다.
    그러나 C Shell에서는 변수에 화일의 경로명이 지정되어 있을때, 경로명중
    특정 부분을 지정하여 참조할 수 있는 기능을 제공한다.
    다음은 그 예를 보여준다.

    ┌─────────────────┐
    │경로명 참조 방식 예제             │
    ├─────────────────┤
    │%set cf=/USAGEII/user1/fileA.c    │
    └─────────────────┘
         (C Shell에서의 기본 프롬프트는 %이다.)

    위의 변수에 저장된 경로명은 다음과 같이 부분적으로 참조 가능하다.

    ┌─────────────────────┬───────┐
    │rOOT                                      │eXTENSION     │
    │/USAGEII/user1/   fileA                     .c            │
    │hEADER          │                                        │
    └────────┤tAIL                                    │
                      └────────────────────┘

    위 도표에서 소문자로 시작되는 문자열이, 경로명의 특정부분을 참조하기
    위한 키워드들이다. 즉; r 문자는 /USAGEII/user1/fileA를,
    h는 /USAGEII/user1/을, t는 fileA를 그리고 e는 .c를 참조하는 키워드이다.
    변수 참조시에 이들 키워드를 지정하는 방식은 다음과 같다.

    ┌─────────────────┬────────────┐
    │Portion of variable               │Specifier               │
    ├─────────────────┼────────────┤
    │root                              │$cf:r                   │
    ├─────────────────┼────────────┤
    │header                            │$cf:h                   │
    ├─────────────────┼────────────┤
    │tail                              │$cf:t                   │
    ├─────────────────┼────────────┤
    │extension                         │$cf:e                   │
    └─────────────────┴────────────┘

    %echo $cf                <--- 전체 경로명을 참조
    /USAGEII/user1/fileA.c
    %echo $cf:r              <--- 화일명까지만 참조
    /USAGEII/user1/fileA
    %echo $cf:h              <--- 부모 디렉토리까지만 참조
    /USAGEII/user1
    %echo $cf:t              <--- 화일명과 확장자만을 참조
    fileA.c
    %echo $cf:e              <--- 확장자만을 참조
    c

C Shell에서도 Bourne Shell에서와 같이 unset 명령어를 사용하여
    변수를 삭제할 수 있다.

    C Shell에서는 하위 쉘에 변수를 전달하기 위해 export 명령어를
    사용하지 않고, 별도로 하위 쉘에 전달할 변수들은 setenv 명령을 통해
    정의해야 하고, unsetenv 명령어를 사용하여 삭제한다.

    다음은 C Shell에서 변수를 제어하는 방식을 보여주는 예이다.

    %set header="USER SUMMARY REPORT"     <-- 변수를 정의
    %echo $header                         <-- 변수의 참조
    USER SUMMARY REPORT
    %unset header                         <-- 변수의 삭제
    %echo $header                         <-- 삭제후 변수 확인
    header:Undefined variable.
    %setenv header "USER SUMMARY REPORT"  <-- 하위 쉘에 전달할 변수를
    %echo $header                             정의한후, 이를 확인하고 있다.
    USER SUMMARY REPORT


---------------------------------------------------------------------------



C Shell의 예약 변수들

    이번 강의에서는 C Shell에서 사용자의 작업 환경을 확립할 수
    있도록 지원하기 위해 제공하는 사전정의형 예약 변수(Reserved
    Variables)에 대해서 설명합니다.
    이들에 대한 자세한 활용예는 후속되는 강의별로 조금씩 소개하고,
    이번 강의에서는 그 종류및 기본적 기능소개에 대해서만 설명합니다.

┌──────┬─────────────────────────────┐
│argv        │쉘 프로그램 실행요구시 명령어 라인상에 함께 제공된      │
│            │인자 리스트를 포함하고 있는 변수.                      
├──────┼─────────────────────────────┤
│cdpath      │cd 명령어의 효율적 사용을 위해 제공되는 변수로,        
│            │cd 명령어의 인자로 제공된 화일을 검색하는데 사용할        
│            │절대 경로명을 갖는 변수이다. 디폴트는 설정되지 않는다.   │
├──────┼─────────────────────────────┤
│cwd         │현재의 작업 디렉토리의 절대 경로명을 갖고있는 변수.    │
├──────┼─────────────────────────────┤
│echo        │요구된 명령어를 실행하기 전에, 입력된 명령어를 화면상에 │
│            │먼저 표시할 것이가를 설정하는 변수. set 되어 있는 경우,  
│            │사용자의 입력 라인이 먼저 표시된후, 실행 결과가 표시된다. │
│            │디폴트는 unset이다.                                 │
├──────┼─────────────────────────────┤
│histchars   │history 기능에서 사용할 대치문자를 재정의하는 변수이다.   │
│            │이 변수에는 두문자를 설정한다. 두문자중 첫번째문자는      │
│            │history 기능에서 !를 대신하여 사용되고, 두번째 문자는     │
│            │^문자를 대신한다.                                         │
├──────┼─────────────────────────────┤
│history     │이전에 수행했던 명령어들을 저장하기 위해, 메모리상에      │
│            │할당되는 history list buffer상에 저장할 명령어의 갯수를   │
│            │선언하는 변수이다. 디폴트는 unset이다.                    │
├──────┼─────────────────────────────┤
│home        │사용자의 홈 디렉토리의 절대 경로명을 갖는 변수.           │
│            │이 변수에 설정되는 절대 경로명은 화일명 확장문자인        │
│            │~으로 참조할수 있다.                                      │
├──────┼─────────────────────────────┤
│ignoreeof   │사용자가 키보드를 통해 ctrl-d (end-of-file)명령을         │
│            │내렸을 경우, 쉘을 종료할 것인가를 설정하는 변수이다.      │
│            │이 변수가 설정된 경우에 사용자는 쉘을 종료하기 위해서     │
│            │exit 또는 logout 명령어를 사용해야만 한다.                │
├──────┼─────────────────────────────┤
│mail        │메일 수신 여부를 확인하기 위해, 쉘에의해 검색될 사용자    │
│            │메일박스의 위치를 선언하고 있는 변수이다. 이 변수에       │
│            │값을 설정할때 메일박스의 경로명 앞에 숫자를 함께 지정하여 │
│            │쉘이 메일박스 검색을 수행할 주기(간격)을 분단위로         │
│            │지정 가능하다.(기본적으로 사용자의 메일박스는             │
│            │/usr/spool/mail/$USER로 할당되기 때문에 이를 설정한다.)   │
├──────┼─────────────────────────────┤
│noclobber   │출력방향 전환시 지정한 출력 화일이 기존에 존재하는 경우   │
│            │이 화일을 덮어쓰게(overwrite)되는데 이를 허용할 것인지를  │
│            │설정하는 변수이다. 디폴트는 unset으로 이 경우 화일을      │
│            │덮어쓴다.                                                 │
├──────┼─────────────────────────────┤
│noglob      │화일명 확장 기능의 허용 여부를 설정하는 변수이다.         │
│            │set되면 화일명 확장 기능은 금지된다.                      │
├──────┼─────────────────────────────┤
│nonomatch   │C Shell에서는 사용자가 화일명의 일정 부분만을 입력한후    │
│            │esc 키를 입력하면, 입력된 부분과 일치하는 문자열을 갖는   │
│            │화일명으로 자동 변경해주는 기능을제공하는데, 이 경우      │
│            │일치하는 문자열을 가진 화일명이 없을 경우에 에러 처리할   │
│            │것인가를 지정하는 변수이다. 디폴트는 unset으로서,         │
│            │에러 처리된후 입력 라인을 종료한다.                       │
├──────┼─────────────────────────────┤
│notify      │사용자가 요구한 작업(통상 백그라운드 작업)이 종료되면     │
│            │즉각적으로 사용자에게 통보할 것인가를 설정하는 변수로,    │
│            │set된 경우 사용자가 요구한 작업이 종료됨과 동시에         │
│            │작업종료를 알려준다. 디폴트는 unset이다.                  │
├──────┼─────────────────────────────┤
│path        │사용자가 입력한 명령어를 찾기위해 검색할 디렉토리들을     │
│            │갖고 있는 변수이다.                                       │
├──────┼─────────────────────────────┤
│prompt      │쉘 프롬프트로 사용할 문자열을 선언하는 변수이다.          │
│            │디폴트는 %이다.                                           │
├──────┼─────────────────────────────┤
│savehist    │history list상에 저장된 이전에 수행했던 명령어들은        │
│            │쉘이 종료함과 동시에 사라지는데, 쉘이 종료하더라도        │
│            │차후에 이들 명령어를 참조하기 위해 사용자의 홈 디렉토리에 │
│            │할당되는 .history 화일에 저장할 수 있는데, 이때 저장할    │
│            │history list상의 명령어 갯수를 설정하는 변수이다.         │
│            │디폴트는 unset이다.                                       │
├──────┼─────────────────────────────┤
│shell       │쉘의 절대경로명을 갖는 변수이다.                          │
│            │디폴트는 /bin/csh이다.                                    │
├──────┼─────────────────────────────┤
│status     직전에 수행했던 명령어의 종료상태가 설정되는 변수.        │
│            │Built-in 명령어의 경우, 정상 수행이면 0이, 비정상 수행이면│
│            │1이 설정된다.                                             │
├──────┼─────────────────────────────┤
│term        │현재 설정된 터미널 Type을 갖는 변수이다.                  │
├──────┼─────────────────────────────┤
│user        │사용자의 로그인명을 갖는 변수이다.                        │
├──────┼─────────────────────────────┤
│verbose     │명령어를 실행시 alias, command, 화일명 그리고 변수 대치를 │
│            │수행하기 전 단계인 history 대치후의 명령어 라인 변환결과를│
│            │화면상에 출력할 것인가를 설정하는 변수로, set되면         │
│            │사용자가 입력한 명령어라인에 대해 history 대치 작업을     │
│            │수행한후, 변환된 라인을 화면에 표시한다.                  │
│            │csh -v의 효과와 같으며, 디폴트는 unset이다.               │
└──────┴─────────────────────────────┘
</pre>