본문 바로가기

Academy I/Tech Academy

Unix 8 쉘프로그래밍

Shell Programming의 일반개요
--------------------------------------------------------------------

1. Shell Programming의 일반개요

    이전 강의에서는 명령어 해독기로서의 쉘을 이용하는데 촛점을 맞추어
    강의를 진행했다. 또한 하나의 명령어 라인에 여러개의 명령어를 실행하는
    방법에 대해서도 설명했다.

    이번에는 화일속에 실행할 일련의 명령어들이나 기존의 명령어들을 조합하기
    위해서 이용하는 쉘 프로그램을 작성하는데 있어서 프로그래밍 도구로
    Bourne Shell을 이용하는 기본적인 방식들에 대해 소개한다.
    이러한 쉘 프로그램들은 사용자에게 복합적인 작업을 실행과 반복적인
    프로시져를 단순하고 빠르게 실행할수 있도록 해준다.

    이번 강의에서 소개되는 주된 내용은 기본적인 쉘 프로그램을 작성및 실행과
    프로그램 문법에러를 검사및 교정방식등이다. 그외에도 다음 방식에 대해
    설명한다.

    .    프로그램안에서 쉘 변수를 사용하는 방법

    .    쉘 프로그램보다 빠르게 실행하고, 일련의 명령어들을 선언하고 있는
         Shell Function의 생성

    .    쉘 프로그램을 실행하는 다양한 방식

    .    쉘 프로그램내에서 수행 가능한 기능들

         -.   사용자로의 프롬프트 표시 기능
         -.   사용자 입력 읽기
         -.   프로그램내에서의 주석(Comments) 지정 방식
         -.   프로그램내에서의 입력 방향전환(Redirection)
         -.   프로그램 흐름 제어(Program Flow Control)

    쉘 프로그램에 대한 자세한 내용은 차후 강의될 쉘 프로그래밍 과정에서
    소개된다.

2. 쉘 프로그램의 작성

    쉘 프로그램 또는 쉘 스크립트는 수행할 일련의 명령어들과 프로그램을
    구성하기 위해 사용한 다양한 프로그램밍 문장들이 포함되어 있는 화일이며,
    이 화일을 실행함으로써 일련의 명령들을 단일 명령어처럼 실행할 수 있다.

    이와 같은 프로그램 화일들은 편집기를 사용하여 실행할 수 있다.
    비록 cat 명령어의 출력 방향전환 기능을 사용하여 짧고 기본적인 프로그램을
    작성할 수는 있지만, 이 경우에는 작성한 프로그램을 수정하거나, 교정하는데
    있어서 제약이 있기 때문에 통상 편집기를 통해 작성한다.

    (주의) 쉘 프로그램의 이름을 쉘 명령어의 이름과 동일하게 부여하는 것은
           피해야 한다. 이유는 처리 내용을 보장하지 못하기 때문이다.

    ( 예제 )

    다음은 cat 명령어와 ed 편집기를 사용하여 동일한 내용의 쉘 프로그램
    화일을 편집하는 과정을 보여주는 예이다.

   이 프로그램에서는 시스템 날짜및 시간 정보를 표시하는 date 명령과
    시스템상의  현재 작업하고 있는 사용자를 확인하는 who 명령어, 사용자의
    현재 작업 디렉토리의 절대 경로명을 알려주는 pwd 명령어, 현재 디렉토리의
    내용을 표시하는 ls 명령어를 지정하고 있다.

    그리고 각 예에서는 실행할 명령어를 하나의 명령어 라인에 ;을 사용하여
    지정하는 예와 각각의 명령어 라인에 지정하는 예를 보여준다.

    ┌──────────────┐
    │   $cat > prog1             │
    │   date ; who ; pwd ; ls    │ cat 명령어의 출력 방향전환을 사용하여
    │   <^d>                     │ 쉘 프로그램을 작성하고 있다.
    └──────────────┘

    ┌───────┐
    │   $ed prog1  │  라인 편집기인 ed를 사용하여 쉘 프로그램을
    │   ?prog1     │  작성하고 있다.
    │   a          │
    │   date       │
    │   who        │
    │   pwd        │
    │   ls         │
    │   .          │
    │   w          │
    │   q          │
   └───────┘


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


Shell Program의 실행 방식과 에러 검증   

Shell Program의 실행 방식과 Debug
--------------------------------------------------------------------

1. Shell Program의 실행

    새로 생성되는 화일에 대해 부여되는 Default Permission(접근권한)은
    rw-rw-rw-로 실행 접근권한을 부여하지 않는다.
    비록 쉘 프로그램에 실행 가능한 명령어들이 들어 있다 하더라도,
    화일에 실행 권한이 부여되지 않기 때문에 실행은 불가능하다.

    이 때문에 프로그램을 실행하기 위해서는 다음과 같은 방식중 하나를
    적용해야 한다.

    .    실행할 명령어들이 들어있는프로그램 화일을 실행하기 위해서
         sh 명령어를 사용한다.

    .    프로그램 화일을 실행하기위해 우선 chmod 명령어를 실행하여,
         실행 권한을 부여한후, 명령어를 실행하는것 처럼 프로그램 화일을
         실행한다.

    sh

    sh 명령어는 마치 명령어들이 터미널에서 입력되어진 것처럼 프로그램
    화일내의 명령어들을 실행한다. sh 명령어는 다른 쉘을 분기한후,
    그 쉘내에서 프로그램을 실행한다. 이때 분기되어 생성된 쉘은, 이를
    서브 쉘이라 한다., 한번에 하나의 프로세스만을 처리할 수 있는
    현재 쉘과 동일한 종류의 쉘로 생성된다.( 현재 쉘의 복사본)
    쉘 프로그램 화일은 하나의 프로세스로 간주되기 때문에 쉘 프로그램내에
    선언되어 있는 모든 명령어들은 서브 쉘에 의해서 실행될 수 있다.
    다음은 sh 명령어를 이용해 쉘 프로그램을 실행하는 예이다.

         $ls -l prog1
         -rw-rw-rw-  1  user1 admin  1672  Jul  7  13:23  prog1
         $sh prog1
         ( prog1 프로그램의 실행 결과가 표시된다. )

    chmod

    chmod 명령어는 명령어처럼 쉘 프로그램을 실행하기 위해 프로그램 화일에
    실행 권한을 부여하기 위해 사용한다. 쉘은 프로그램 화일을 실행하기 위해
    새로운 서브 쉘을 분기한다. 이때 분기되어지는 서브 쉘은 현재 쉘과 동일한
    종류의 쉘로서 분기된다. chmod 명령어에 접근 권한을 지정하기 위해
    8진수 또는 심볼릭 기호를 사용할 수 있다. 다음 예는 chmod 명령을 이용해
    쉘 프로그램을 기동하는 방식을 보여준다.

         $chmod 744 prog1
         $ls -l prog1
         -rwxr--r--  1  user1  admin  1672  Jul  7  13:23  prog1
         $prog1
         ( prog1의 출력이 표시된다. )

    이 예에서 prog1 화일에 소유자 실행 권한을 부여하기 위해 8진수로 744라는
    접근권한을 지정하고 있다. 그후 prog1 화일을 실행한다.

2. 쉘 프로그램의 대체 실행방식

    명령어나 프로그램 화일이 실행될때, 쉘은 쉘 명령어 실행때와 마찬가지로
    디스크상에서 지정한 화일명을 갖는 프로그램 화일을 검색한다.
    쉘이 해당 프로그램을 발견하면은, 명령어 라인 처리를 계속하고,
    프로그램을 실행하기 위해서 새로운 프로세스를 분기한다.

    새로운 프로세스를 분기하지 않고 프로그램을 실행하기 위해서는
    .(dot) 와 exec 명령어를 사용한다.

    .(dot)

    .(dot) 명령어는 쉘 프로그램이 종료된후에도 실행을 계속하기 위해서
    현재의 프로세스 일부로써 쉘 프로그램을 실행한다. . 명령을 이용하여
    쉘 프로그램을 실행할 경우에는 실행 권한을 필요로 하지 않는다.
    그러나 컴파일된 프로그램들은 . 명령을 이용해 실행할 수 없다.

    이 명령어의 형식은 ". program" 형식으로 실행한다.

    exec

    exec 명령어는 쉘의 일부로써 제공되는 몇가지 고유의(Built-in) 쉘 명령어중
    하나이다. 프로그램은 쉘에 즉시 유효하기 때문에, 새로운 프로세스는
    프로그램을 실행하기 위해 분기되지 않는다.

    exec 명령어는 현재의 프로세스를 덮어씌우고, 대치하며 지정한 프로그램을
    실행한다. 그러나 이 경우 프로그램이 종료한후 제어가 본래의 쉘에
    되돌려지지 않는다. 즉 이는 프로그램 실행을 개시할때 위치하던 쉘은
    종료된다는 것을 의미한다. exec 명령어는 프로그램을 실행하기 위해
    실행 권한을 필요로하지 않는다.
    또한 이 명령은 컴파일된 프로그램도 실행할 수 있다.

    이 명령의 사용 형식은 "exec program"의 형식이다.

3. 프로그램 에러 검증

    sh 명령어는 또한 프로그램 에러를 발견할 수 있다. 이 명령은 프로그램내에
    에러의 위치를 찾기위한 두가지의 유용한 옵션을 제공한다.
    이 두 옵션은 단독으로 또는 함께 지정하여 사용할 수 있다.

    -v   실행되는 각각의 라인을 표시한다.
    -x   실행되는 명령어와 인자들을 표시한다.

    프로그램내의 에러는 편집기를 사용하여 교정할 수 있다.

    sh 명령어의 옵션은 일반적으로 복합 프로그램에서 사용된다.

    ( 예제 )
            ┌────────┐
            │  $sh -v prog1  │
            │  $sh -x prog1  │
            │  $sh -xv prog1 │
            └────────┘


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



Shell Programming의 기초 : Variables
--------------------------------------------------------------------

1. 변수(Variables)

    변수는 변경할 수 있는 정보를 갖고있는 메모리내의 지정된 기억 영역이다.
    변수는 긴 정보 또는 수시로 변경되는 정보를 참조하기 위해서 프로그램에서
    자주 사용된다. 변수에는 다음과 같은 4가지 종류가 있다.

         지정 변수(Named Vriables)
              사용자에 의해 정의되고, 변경되는 변수

         쉘 변수(Shell Variables)
              쉘에 의해 정의되고, 사용자에 의해 변경될 수 있는 변수

         특수 변수(Special Variables)
              쉘에 의해 정의되고, 사용자에 의해 변경될 수 없는 변수

         포지셔널 파라메터(Positional Parameter)
              프로그램에서 참조되는 변수; 이 변수에는 명령어 라인에서 지정된
              각각의 인자들이 설정된다.

    변수와 변수에 설정된 값들은 로그인 세션 동안의 현재 프로세스에게만
    (current process) 유효하다. 그러나 변수는 export 명령어를 사용하여
    다른 프로세스에 전달할 수 있다. 또한 변수는 .profile내에 정의해 둠으로써
    로그인시에 자동적으로 정의할 수 있다. 사용자가 특정 변수에 정의되어 있는
    변수의 내용을 확인하기 위해서는 echo 명령어를 사용하고, 변수를 삭제하기
    위해서는 unset variable_name 형식으로 unset 명령어를 사용한다.

    변수와 관련된 자세한 내용은 이후 하나씩 설명한다.

2. 지정 변수(Named Variables)

    이 변수는 사용자에 의해 정의되고, 사용자가 변경할 수 있다.
    지정 변수를 정의하는 양식은 다음과 같다.

         variable_name=value

    variable_name은 문자 또는 밑줄 문자로 시작하는 공백이 아닌 일련의
    문자들로 구성될 수 있고, variable_name과 value 사이의 =의 전후에는
    공백을 사용할 수 없다. 그리고 value에 명령어 라인상의 옵션과 인자들처럼
    공백이 있거나, 공백으로 구분되는 단어로 구성된 문자열을 지정할 경우에는
    보호문자를 사용하여 묶어주어야 한다. 이때 보호문자로 따옴표, 쌍따옴표,
    역따옴표를 사용할수 있는데, 이중에서 역따옴표는 명령어 대치를 수행하는
    부가적인 기능을 수행한다. 예를들면 var=`pwd`라 지정할 경우에는
    var라는 변수에 pwd라는 문자열이 설정되는 것이 아니라, pwd 명령을
    실행한 결과가 설정된다. 변수 설정시 주의할 것은 value로서 파이프 문자,
    방향전환 문자 또는 & 심볼과 같은 특수 문자는 사용할 수 없다는 것이다.

    이러한 변수의 정의는 쉘 프롬프트상에서 입력할 수도 있고, 로그인시
    자동적으로 설정하기 위해 .profile에 선언해 둘수도 있다.

    다음은 지정변수를 정의하는 예이다.

         $var=1991
         $ll=`ls -al`
         $msg="Reminder: Staff meeting today at 4 p.m."

    위의 첫번째 예에서 변수에 숫자형식의 문자열을 할당한다.
    두번째 예에서는 ls -al 명령의 실행 결과를 ll이라는 변수에 할당한다.
    마지막 예는 일련의 문장을 msg라는 변수에 설정하는 것을 보여준다.
    이 예에서 문장 가운데 공백이 있음으로 인해 쌍따옴표로 묶은 것을
    주목하기 바란다.

    정의된 변수를 참조하는 방식은 이후 설명한다.

3. 쉘 변수(Shell Variables)

    쉘은 사용자의 쉘 환경과 연관되는 정보들을 갖고 있는 변수들을 제공한다.
    이 변수들은 쉘에의해 로그인 초기에 설정된다. 그러나 사용자에 의해 변경도
    가능하다. 예를들면, 사용자의 홈 디렉토리 또는 쉘 프롬프트를 설정하기
    위해 쉘은 이 변수들을 이용한다.

    쉘 변수의 형식은 지정 변수와 유사하다.

         shell_variable_name=value

    쉘 변수의 이름은 모두 대문자인 것을 주목해야 하며, 지정 변수에서와
    마찬가지로 =을 전후해 공백을 지정할 수 없고, 공백이 들어있는 value를
    지정하기 위해서는 바듯이 따옴표로 묶어 주어야 한다.

    쉘 변수의 값을 변경하기 위해서 쉘 프롬프트에서 새로운 값으로 기존의 값을
    대치한다. 예를들면, PS1="cmd? "라고 지정하면, 통상 $로 표시되는
    프롬프트가 PS1 변수에 설정된 cmd? 라는 프롬프트로 바뀌게 된다.

    일반적으로 많이 사용되는 쉘 변수와 설정되는 값은 다음과 같다.

    HOME           로그인시 위치하는 홈디렉토리의 경로명
    IFS            쉘에의해 사용되는 내부적인 필드 구별자
    LOGNAME        사용자의 로그인 명
    LPDEST         사용자가 프린트 요구시 관리자에 의해 지정된
                   디폴트 프린터로 출력되는데 이 경우 사용할 다른 프린터 명
    MAIL           사용자의 메일 화일명(사서함)
    PATH           명령어 실행시에 검색되는 디렉토리들의 목록
    PS1            쉘의 기본 프롬프트
    PS2            쉘이 추가적인 입력을 요구할때 표시되는 서브 프롬프트
    TERM           터미널 이름

4. 특수 변수(Special Variable)

    쉘에 의해 설정되고, 읽기전용 특수 변수는 명령어 라인과 명령어 실행의
    상태에 대한 정보를 갖고있다. 이 변수의 값은 사용자에 의해 변경될 수
    없다.

    빈번히 사용되는 특수 변수는 다음과 같다.

    $#        쉘에 의해 명령어 라인 인자(Arguments)의 갯수가 설정된다.
    $*        쉘에 의해 모든 명령어 라인 인자들이 설정된다.
    $0        쉘에 의해 현재의 프로그램 이름이 설정된다.
    $$        현재 실행중인 프로세스의 PID가 설정된다.
    $!        직전에 background에서 실행된 프로세스의 PID가 설정된다.

5. 포지셔널 파라메터(Positional Parameter)

    포지셔널 파라메터는 변수의 또다른 종류이다. 포지셔널 파라메터에 설정되는
    값은 명령어 라인에 지정된 인자들이 쉘에의해 차례대로 할당되어 진다.
    이 변수는 쉘 프로그램에서 자주 사용된다.

    명령어 라인은 128개의 인자를 가질수 있는 반면에, 쉘은 변수 $1부터
    $9 까지의 9개의 포지셔널 파라메터에 명령어 라인의 처음 9개의 인자들의
    값만을 저장한다. 그런이유로 쉘 프로그램은 9개의 인자만을 참조한다.
    예를들면, 명령어 라인에서
                   ┌────────────┐
                   │  prog2 arg1 arg2 arg3  │라고 지정하였다면
                   └────────────┘
    arg1은 $1 변수에, arg2는 $2 변수에 그리고 arg3는 $3 변수에 저장된다.

    이미 설명한 쉘 변수인 $*는 명령어 라인에 기술된 모든 인자가 한꺼번에
    설정되며, $# 변수는 명령어 라인의 인자의 갯수가 설정된다.

    shift 명령어는 포지셔널 파라메터로 설정되는 9개의 인자 이외의 인자들을
    참조하기 위해 사용한다. 프로그램에서 처음 실행한 shift 명령어를 사용하면
    10번째 인자를 참조할 수 있게 된다. 여러번 shift 명령어를 사용함으로써
    그외의 인자들도 억세스할 수 있다.

    위의 예에서 한번의 shift 명령을 사용했다고 가정하면,
    arg2가 $1에 저장되고, arg3가 $2에 저장된다. 이로인해 arg1은
    참조 불가능하게 된다.


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



쉘 프로그래밍의 기초: 변수의 참조 및 export
--------------------------------------------------------------------

1. 변수(Variables)의 참조 방식

    변수의 내용을 참조하는 방식에는 다음과 같은 2가지가 있다.

    . 변수값으로 명령어를 갖고있는 변수의 명령어 출력을 표시하기 위해서는
      변수명의 앞에 $ 심볼을 붙여 참조한다.

      예를들어, 이전 강의에서 소개됐던 현재의 디렉토리내의 내용에 대한 자세한
      출력을 표시하기 위해 생성했던 ll=`ls -al` 변수를 보자.
      만약 사용자가 명령어 라인에 $ll /etc라고 지정하면, /etc 디렉토리의
      자세한 내용을 표시된다. 이와같이 운용되는 지정 변수들은 복합적인
      명령어 구조의 축약형으로써 유용하다.

    . 변수에 설정되어 있는 값을 표시하기 위해서는 echo 명령어와 함께
      $ 심볼을 사용한다.

      echo 명령어는 자신의 인자를 표준출력으로 표시한다.
      예를들어 지난 강의에서 정의했던 var1 변수를 보자. 명령어 라인에
      echo $var1이라고 지정하게 되면, 쉘은 echo 명령어에 지정되어 있는
      $var1을 변수명으로 인식하여, $var1 대신에 지정 변수 var1에 설정되어
      있는 값인 1991로 대치한다. 그후 쉘은 인자로서 1991을 echo 명령어에
      전달함으로써 터미널에는 1991이라는 출력이 표시된다.

      echo 명령어는 역슬레쉬(\)가 선행하는 몇개의 문자들에 대해 특별한 의미를
      부여한다. 그런데 이런 문자에서 사용하는 역슬레쉬는 쉘에 의해 또다른
      의미가 부여되어 있음으로, 이 문자들을 echo 명령어가 처리하도록 하기
      위해서는 반드시 따옴표로 묶어주어야 한다. echo 명령어에 의해 특수한
      의미가 부여되는 문자들은 다음과 같다.

         \n        새로운 라인으로 이동한다. 즉; \n 문자가 지정된 이후의
                   문자열은 다음 라인에 표시된다.
         \t        다음 탭(tab)의 위치만큼 간격을 벌려 출력한다.
         \c        동일 라인에 출력을 계속하여 출력한다.

    다음은 변수를 참조하는 방식을 보여주는 예이다.

    ┌─────────────────────┐
    │   $dir=`pwd`                             │
    │   $echo My current directory is $dir     │
    │   My current directory is /home/user1    │
    └─────────────────────┘

    변수의 명령어 대치를 보여주는 예이다. dir이라는 변수에 pwd 명령어가
    변수값으로 설정되었다. 이때 주목할 것은 pwd 명령어를 역따옴표로
   둘러 쌓고 있다는 것이다. 이렇게 지정하면 쉘은 변수값으로 pwd 명령어의
    실행 결과를 지정변수에 저장한다. 그리고 echo 명령어를 통해 변수의 내용을
    확인하고 있다.

    ┌─────────┐
    │   $echo $PS1     │
    │   $              │
    └─────────┘

     이 예는 PS1이라는 쉘 변수에 설정되어 있는 기본 프롬프트를 확인하는
     예이다. 이 예에서의 두번째 라인의 $ 표시는 프롬프트가 아니라,
     echo 명령의 실행 결과의 출력임을 유의하기 바란다.

   ┌────────┐
   │   $echo $$     │ 이 예는 특수 변수인 $$의 내용을 참조하는 방식을
   │   485          │ 보여주는 예이다. 이 변수에는 현재의 프로세스 식별자가
   └────────┘ 설정된다.

    ┌─────────────────┐
    │    $echo 'Skipping a\n\nline'    │ 이 예는 echo 명령어에 의해
    │    Skipping a                    │ 사용되는 특수문자(\n)의 사용예를
    │                                  │ 보여주고 있다.
    │    line.                         │ 여기서 \n은 새로운 라인으로의
    └─────────────────┘ 이동을 의미한다.


2. 변수의 export

    로그인시에 사용자를 위해 /etc/passwd 화일에 지정된 쉘 프로그램의 복사본이
    실행된다. 이 쉘 프로세스는 시스템 상의 다른 사용자들과 별개의 사용자의
    운영 환경을 유지관리한다. 사용자는 쉘 변수를 통해 자신만의 고유한 환경을
    설계할 수 있다. 변수 할당을 통해 설계한 작업 환경은 사용자가 logout을
    실행할 때까지 유지관리된다. 그런데 주목할 것이 있다. 변수 할당은 현재의
    프로세스내에서만 유효하다는 것이다.

    하나의 프로그램이 실행되면, 자식 프로세스가 분기된다.
    이때 부모 프로세스는 자식 프로세스에게 이런 변수들의 값을 자동적으로
    전달하지 않는다. 이로인해 자식 프로세스는 부모 프로세스내에 할당되어
    있는 변수 할당을 알지 못하게 되며, 더우기 자식 프로세스는 부모 프로세스에
    선언되어 있는 변수의 값을 변경할 수 없다.

    다음은 이상에서 설명한 내용을 보여주는 예이다.

    ┌────────────┐  이 예에서 기본 프롬프트를설정하기 위한
    │   $PS1='my_prompt> '   │  쉘 변수인 PS1에 my_prompt> 라는 새로운 값을
    │   my_prompt> sh        │  할당했다. 그후 프롬프트가 다르게 표시되는
    │   $exit                │  것을 확인할 수 있다. 그후 sh 명령어를
    │   my_prompt>           │  사용하여 자식 프로세스를 기동하니,
    └────────────┘  자식 프로세스가 기동된 후에는 다시
     프롬프트가 $로 바뀌게 되는 것을 보여준다. 이는 부모 프로세스에 설정된
     my_prompt> 가 자식 프로세스에 전달이 되지 않았기 때문이다.
     끝으로 자식 프로세스를 종료하여, 부모 프로세스를 재기동하니까, 이전에
     설정했던 프롬프트가 계속 유지되고 있는 것을 확인할 수 있다.

    export 명령어

    export 명령어는 쉘 프로그램에서 정확한 변수 대치를 위해 중요한 역할을
    수행한다. export 명령어는 자식 프로세스에 변수값의 복사본을 전달한다.
    자식 프로세스는 자신이 사용하기 위해 변수의 복사본을 받아 들인다.
    비록 자식 프로세스가 복사본의 값들을 변경한다 하더라도, 부모 프로세스내의
    변수들은 변경되지 않고 유지된다. vi 프로그램은 실행될때 터미널의 용량을
    알아야 하기 때문에 TERM 변수에 터미널 종류가 설정되어 있어야 하며, 또한
    TERM 변수의 값은 vi 프로그램은 자식 프로세스로 분기되어 실행되기 때문에
    export 되어야만 한다.

    export 명령어의 형식은 다음과 같다.
    ┌──────────────┐
    │   export variable_name     │
    └──────────────┘

    export 명령은 변수의 선언 명령과 세미콜론을(;) 사용하여 동일한 명령어
    라인에 지정할 수도 있고, 각각 다른 명령어 라인에 지정할 수도 있다.
    다음은 export 명령어를 사용하는 예를 보여준다.

    ┌────────────────────┐
    │   $PS1='cmd> '                         │
    │   cmd> export PS1                      │
    │   cmd> sh                              │
    │   cmd> PS1='subprompt> ' ; export PS1  │
    │   subprompt> sh                        │
    │   subprompt> exit                      │
    │   subprompt> exit                      │
    │   cmd>                                 │
    └────────────────────┘

    이 예의 처음에서 PS1이라는 변수에 cmd1> 이라는 값을 지정함으로써
    기본 프롬프트를 바꾸고 있다. 그리고 export 명령을 통해서 프롬프트를
    export시킨후, sh 명령을 통해 자식 프로세스를 분기 하였다. 그런데
    새로운 프로세스에서도 동일한 프롬프트가 사용되는 것을 볼 수 있다.
    이는 변수의 값이 export되었다는 것을 의미한다. 그리고 자식 프로세스에서
    또한번 프롬프트를 재정의하고 이를 export하였다. ( 이때 변수의 선언과
    export 명령어가 ;을 사용하여 동일 라인에서 선언되고 있음을 주목하기
    바란다.) 그후 또다시 자식 프로세스를 분기하여 export 여부를 확인하였다.
    그런다음 각각의 자식 프로세스를 종료하며 프롬프트가 변경되는 상황을
    확인하니 가장 처음의 프로세스에서는 아직도 cmd> 프롬프트가 유지되고
    있음을 확인할 수 있다. 이는 export의 방향은 상위 프로세스에서
    하위 프로세스로만 행해진다는 것을 알게 해준다.

3. 환경 변수의 표시

    사용자의 환경을 표시하거나 수정하기 위한 명령어는 다음과 같다.

    . set 명령어

         인자를 지정하지 않은 set 명령어는 현재의 환경에서 존재하는
         모든 변수들의(export 여부에 관계없이) 목록을 표시한다.
         set 명령어는 또한 명령어와 인자들을 프린트 할것인지를 설정하기
         위한 쉘 옵션을 설정하기 위해, 또 포지셔널 파라메타를 재할당하기 위해
         사용될 수 있다.

    . env 명령어

         인자를 지정하지 않은 env 명령어는 현재 환경에서 export 되어진
         변수들을 표시한다. env 명령어는 또한 지정한 명령어의 실행동안 현재의
         환경을 수정하기 위해 사용할 수 있다.


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



쉘 프로그래밍의 기초: shell function과 .profile
--------------------------------------------------------------------

1. Shell function

    Shell function은 쉘 프로그램과 비슷하게 실행하기 위한 일련의 명령어들을
    갖고 있다. 그러나 Shell function은 변수와 같이 메모리에 저장되기 때문에
    쉘 프로그램보다 더욱 빨리 억세스및 실행될 수 있다.
    그리고 Shell Function은 현재의 쉘내에서 실행된다.

    Function을 정의하기 위한 형식은 다음과 같은 두가지 방식이 있다.

    형식 1)

    ┌──────────┐
    │   function_name()  │
    │   {                │
    │   command1         │
    │   command2         │
    │   command3         │
    │   }                │
    └──────────┘

    여기서 function_name은 나열되어 있는 명령어들을 실행하기 위해
    function을 호출하기 위한 이름으로 사용된다. 그리고 연이어 기술되어 있는
    둥근괄호'()'는 쉘에게 연이어 function의 정의가 뒤따르고 있다는 것을
    알려준다. 그리고 실행할 명령어들은 { 와 } 심볼로 둘러 쌓는다.
    function은 function_name을 입력함에 의해서 명령어 처럼 실행된다.

    형식 1로 function을 정의하는 예이다.
    ┌──────────────────────┐
    │   $f1 ()                                   │
    │      {                                     │
    │      date                                  │
    │      who                                   │
    │      ls -F                                 │
    │      }                                     │
    │   $f1                                      │
    │    ( Function을 실행한 결과가 출력된다. )  │
    └──────────────────────┘

    형식 2)

    function_name() { command1 ; command2 ; command3; }

    이 형식은 하나의 명령어 라인에 짧은 function을 정의하는데 유용하다.
    이 형식에서 첫번째 명령어의 앞에 공백을 두어야 한다. 세미콜론으로
    각각의 명령어를 구분하고, } 심볼이 동일라인에 지정될 경우에는 반드시
    마지막 명령어 다음에 세미콜론을 지정해야 한다.

    다음은 형식 2로 function을 정의하는 예이다.

    ┌─────────────────────┐
    │   $f1 () { date ; who ; pwd ; ls -r ; }  │
    │   $f1                                    │
    │   (Function을 실행한 결과가 출력된다. )  │
    └─────────────────────┘

    Function은 변수와 같이 unset function과 처럼 unset 명령어에 삭제할
    function_name을 지정함으로써 삭제할 수 있다. function은 로그인시에
    자동적인 실행을 위해 .profile에 선언된 경우를 제외하고는,
    현재의 로그인 세션내에서만 유효하다.

2. 로그인 환경의 수정: .profile

    로그인 작업이 수행되는 동안 모든 사용자를 위해 전반적인 시스템 환경을
    설정하기 위해 시스템 /etc/profile이 실행된다. /etc/profile은 또한 news,
    mail, stty 그리고 umask 같은 몇가지의 명령어를 실행한다. /etc/profile은
    시스템 전반의 사용자 환경을 정의하기 위해 시스템 관리자에 의해
    수정되어질 수 있다. 부가적으로 만약 사용자의 홈 디렉토리에 .profile이
    있으면, 그 화일도 로그인시에 실행된다. 이때 .profile의 내용이
    /etc/profile의 내용을 덮어 씌운다.

    .profile은 쉘 프로그램이다. 시스템 관리자는 사용자 계정이 생성되었을때
    표준 형식의 .profile을 할당할 수 있다. 시스템에서 제공하는
    표준 .profile의 형식은 다음과 같다.

    ┌───────────────────────────────┐
    │   #This is the default standard profile provided to a user.  │
    │   #They are expected to edit it to meet their own needs.     │
    │                                                              │
    │   MAIL=/user/mail/${LOGNAME:?}                               │
    └───────────────────────────────┘

    .profile에는 이전에 강의되었던 명령어들, 쉘 프로그램, 변수 또는
    function들을 포함시킬수 있다. .profile의 예는 다음과 같다.

    ┌────────────────────────┐
    │   $cat .profile                                │
    │   PATH=:$HOME/local_bin:/bin:/usr/bin:/etc     │
    │   MAIL=/var/mail/logname                       │
    │   TERM=uvt1224                                 │
    │   PS1="Yes? "                                  │
    │   PS2="more: "                                 │
    │   export PATH MAIL TERM PS1 PS2                │
    │   f1 () { date ; pwd ; ls -al | pg; }          │
    │   script4                                      │
    │   echo HAVE A SUPER DAY ! ! !                  │
    └────────────────────────┘


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


Shell Program의 장식 기능들    

쉘 프로그래밍의 장식요소
--------------------------------------------------------------------

1. 쉘 프로그래밍의 장식 요소들

    쉘은 더욱 유용하고 융통성 있는 프로그램을 마들수 있도록 쉘 프로그램을
    장식할 수 있는 여러가지 기능들을 제공한다. 이번 강의에서는 보다 진보된
    쉘 프로그램을 작성하기 위해 사용되는 두드러진 기능들에 대해 설명한다.
    이들에 대한 자세한 운용형식에 대해서는 쉘 프로그래밍 과정에서 설명한다.

    . echo

         echo 명령어는 프로그램을 실행하는 사용자에게 메세지를 표시하기 위해
         프로그램내에서 사용될 수 있다.

         예를들면 echo Enter something라 지정하면, 프로그램이 실행 되었을때
         화면상에 Enter something라는 메세지를 표시하게 된다.

    . read

         read 명령어는 사용자의 입력을 받아들이는 쉘 프로그램을 작성할 수
         있도록 해준다. 또한 사용자의 입력을 지정한 변수에 저장해 줌으로써
         프로그램내에서 참조할 수 있게 해준다.

         예를들어 프로그램에서 read text라 지정한후 실행하면, 사용자가
         입력한 전체의 입력 라인을 text 변수에 저장한다.

    . sleep

         이 명령어는 지정한 시간(단위:초)동안 실행을 중지한다.
         이 명령은 프로그램 실행중간에 실행을 중지하기 위해 사용한다.

         예를들면 sleep 8이라고 지정하면, 8초동안 실행을 중지한다.

    . 주석(Comments)

         프로그램내에 프로그램내의 특정 부분에 대한 설명 정보를 기술할수
         있다. 프로그램내의 여러 장소에 지정되는 주석은 지정 위치의
         프로그램 부분이 수행하는 작업에 대한 서술 형식의 정보를 제공함으로써,
         프로그래머의 프로그램 검증및 유지 보수등에 효율성을 제공한다.
         쉘 프로그램에서는 # 심볼 이후에 기술되는 텍스트들을 주석처리한다.
         쉘에의해 # 심볼 이후의 문자들은 무시되며, 프로그램 실행시 처리되지
         않는다.

         예를들면, 다음과 같다.

         #The statement below tests for condition A
         #and execute the commands that follow

    . Here 기능

         Here documents 기능은 쉘 프로그램내에서 입력 방향전환을 수행할 수
         있게 해준다. 이 기능에서 사용하는 입력 방향전환 심볼인 << 는
         지정한 구별자 사이의 모든 내용을 프로그램의 표준 입력으로써
         처리할 것을 쉘에게 지시한다.

         Here documents의 사용 형식은 다음과 같다.

         ┌─────────┐   이 형식에서 !는 구별자로 사용되고 있다.
         │  command <<!     │   이 구별자는 사용자 임의대로 지정할 수
         │  (입력 라인들)   │   있다. 좌측의 형식에서 알수 있듯이
         │  !               │   첫번째 !와 두번째 !사이의 입력된 라인들이
         └─────────┘   command의 표준 입력으로 처리된다.

    . Looping

         Looping 문장은 지정한 횟수만큼 또는 지정한 조건을 만날때까지
         일련의 명령어들을 반복적으로 실행한다.  쉘 프로그램에서는 3가지
         Built-in looping 명령어들을 사용할 수 있다. for, while 그리고
         until등이다. 다음은 이들에 대한 설명인데, 이 형식에서 각라인에서
         첫번째 기술되는 지시자는 반드시 지정하여야 한다.

         for 문장은 지정한 명령어를 지정횟수만큼 실행한다.

              for variable in argument list
              do
                   command_list
              done

         while 문장은 지정한 조건이 참인동안 지정된 명령어들을 실행하고,
       조건을 만족하지 못하는 경우에는 실행을 종료한다.

              while test command true
              do
                   command list
              done

         until 문장은 while 문장과 반대의 경우이다. 즉; 이문장은 주어진
         조건이 참이될때까지 지정한 명령어들을 실행한다.

              until test command true
              do
                   command list
              done

         Looping 문장의 실행은 break나 continue 명령을 사용하여 제어를
         할 수 있다. break 문장은 loop를 종료하고, done 문장 이후에
         지정된 문장으로 제어를 옮기고, loop를 종료한다.
         continue 문장은 done 문장으로 제어를 옮기고, loop의 실행을 계속한다.

    . 조건 제어

         조건 제어문은 검사 조건을 기준으로 프로그램의 흐름을 제어할 수 있게
         해준다. 다음은 조건 제어를 수행하여 프로그램의 흐름을 제어할 수
         있도록 지원하는 제어문들이다.

         if-then-fi 제어문

         if-then-fi 제어문은 지정한 조건을 검사하고, 조건이 참일 경우에
         then 문장에 지정되어 있는 명령어들을 실행한다. 거짓이면 fi 이후에
         지정된 라인으로 제어를 넘긴다. 형식은 다음과 같다.

              if test command(s) true
                   then command list
              fi

         if-then-else-fi 제어문

         if-then-else-fi 제어문은 지정한 조건의 검사를 수행한후 조건이
         참이면, then에 지정된 명령어들을 실행하고, 거짓이면 then문에
         지정된 명령어들은 생략하고, else에 지정된 제어문을 실행한다.

              if test command(s) true
                   then command list
                   else command list
              fi

         case 제어문

         case 제어문은 지정한 변수의 값을 여러개의 패턴의 값들과 비교하여
         변수값과 일치되는 패턴을 발견하면, 패턴별로 별도로 지정되어 있는
         명령어들을 실행한다. 그리고 패턴 선언시 * 문자를 사용하여, 일치하는
         패턴을 발견하지 못했을 경우 실행할 명령어들을 따로 지정할 수 있다.
         그 예는 다음과 같다.

              case test value in
                   pattern1) command list ;;
                   pattern2) command list ;;
                   *)        command list ;;
              esac

         쉘 프로그램을 작성하기 위해서 위에서 설명한 제어문말고도 다양한
         형태의 변형된 제어문을 사용할 수 있다. 또한 중첩된 제어문들도 사용
         가능하다. 자세한 사항은 새롭게 강의될 유닉스 쉘 프로그래밍 과정에서
         다시 설명한다.


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



쉘 프로그래밍의 사전 지식
--------------------------------------------------------------------

1. Shell

    1960년대 후반 유닉스가 개발된 이래, 사용자의 작업을 돕기위한 몇가지
    다른 인터페이스(Interface)가 개발되었다. 이러한 인터페이스(즉; 쉘)들은
    더욱 사용자에 친숙한 운영체제로써 유닉스를 만들기 위하여 계속적으로
    갱신및 수정되었다.

    가장 널리 알려진 쉘은 1970년 초반 Stephen Bourne에 의해 개발된
    Bourne Shell이다. 이 쉘은 모든 유닉스 시스템에서 사용가능하다.
    이 쉘은 인터페이스로서 최소 기능들만을 갖고 있으며, AT&T의 Bell 연구소에
    의해 계속 개선되었다.

    또하나 널리 알려진 쉘이 1970년대 초반 켈리포니아 버클리 대학의
    Bill Joy에 의해 생성된 C Shell이다. 이 쉘은 Bourne Shell에
    Command history와 C 프로그래밍과 유사한 문법 구조와 같은 부가적 기능을
    갖도록 개량한 것이다. C Shell은 추가한 기능들로 인해 Bourne Shell보다
    처리속도가 느리다.

    C Shell은 확실히 Bourne Shell에 비해 매우 친숙한 사용자 인터페이스이다.
    그렇지만 이 두 쉘의 문법은 많은 차이가 난다. 따라서 이들간의 차이로인해
    사용자는 새로운 내용을 익혀야 하는 수고가 요구된다.

    그러나 걱정하지 마라. Korn Shell이 있다. 이 인터페이스 즉; Korn Shell은
    AT&T Bell 연구소의 David Korn에 의해 개발되었다. 이 쉘은 Bourne Shell을
    기반으로 한다. 그렇지만 사용자에 친숙한 C Shell의 기능들을 포함하고 있다.
    이 쉘은 Bourne Shell이나 C Shell보다 프로그램 규모가 크다. 그렇지만
    프로그램 크기로 인한 처리속도의 저하를 방지하기 위해, Korn Shell 옵션을
    제공한다. 이를 사용하여 명령어 처리 속도를 빠르게 할 수 있다.

    이전에는 Korn Shell은 유닉스의 하나의 개별적인 펙키지처럼 이용되었기
    때문에 사용자가 사용이 불편했으나, 유닉스 SVR4.0 버전에는 Korn Shell이
    포함됨으로써 사용자는 보다 쉽게 Korn Shell을 이용할 수 있게 되었다.
    비록 SVR4.0 버전에서 Bourne Shell이 Default Shell이지만, 사용상의
    편리함으로 인해 Korn Shell은 보다 많은 유닉스 사용자층을 확보하게 될
    것이다. 이번에 강의될 유닉스 쉘 프로그래밍 과정에서는 Bourne Shell과
    Korn Shell을 기준으로 강의가 진행될 것이다. C Shell에 관한 내용은
    강의의 마지막 부분에서 따로 특징적인 기능들만을 소개할 것이다.

2. 연산자(Operator)

    Bourne Shell과 Korn Shell은 쉘에 특별한 의미를 갖는 일련의 연산자들을
    갖고있다. 이러한 연산자들의 정확한 의미와 예는 이후의 강의에서
    하나씩 소개될 것이다.

    이런 연산자들은 실행 내용에 따라 입출력 방향전환 연산자와 제어 연산자,
    두 종류로 나눌수 있다. 그리고 이들 연산자들을 사용함에 있어서 연산자
    전후에 공백을 지정한다. 그러나 이들 공백은 필수 지정 요소는 아니다.
    관습에 의한 사용이다. 그렇지만 && 또는 >&와 같이 조합된 두문자가 하나의
    연산자를 나타낼 경우에, 이 문자들 사이에 공백을 지정하면 않된다.

    (1) 입출력 방향전환 연산자( I/O Redirection Operators)

         - Bourne Shell에서 제공하는 연산자들

              >    >>   >&   <    <<   <<-  <&

         - Korn Shell에서 제공하는 연산자들

              Bourne Shell에서 제공하는 연산자 모두
              >|   <>

    (2) 제어 연산자( Control Operator )

         - Bourne Shell에서 제공하는 연산자들

              |    &    ;    (    {    ||   &&   ;;   )    }

         - Korn Shell에서 제공하는 연산자들

              Bourne Shell에서 제공하는 연산자들
              ((   ))   |&

3. 예약어 ( Reserved Words )

    예약어는 시스템에서 보통의 단어들과는 다르게 인식된다. Bourne과
    Korn Shell은 이들 예약어가 명령어 라인상, 다른 예약어 직후 또는
    제어 연산자의 직전에 첫번째 단어로 지정되었을 경우에, 이 예약어에
    부여되어 있는 의미에 따라서 작업을 실행한다.

    명령어가 복합 명령어(Compound Command)인 경우에는,
    어떤 예약어는 다른 예약어 이후의 세번째 위치에 있을 경우에만 예약어로
    인식된다. 예를들면, case, for 그리고 select는 그들을 사용할때 3번째
    단어로서 in을 요구하는 예약어들이다. 이때 in은 이들 명령어 사용시
    3번째 단어로 지정되어야만 예약어로 인식되는 예약어이다.

    예약어들은 보호문자( ',",` 와 \와 같은)내에 지정된 경우에는 일반 문자로
    처리되고, 예약어로 처리되지 않는다.

    다음은 쉘 예약어들이다.

    - Bourne Shell에서의 예약어

         {      }      case    do     done     elif      else      esac
         fi     for    if      in     then   until     while

    - Korn Shell에서의 예약어

         Bourne Shell에서의 예약어 전부
         function       select         time       [[       ]]

4. Korn Shell의 Alias

    Korn Shell은 빈번하게 실행하는 명령어 라인에 대해서 축약형식의
    명령어 이름을 부여할 수 있는 기능을 제공한다. 이렇게 부여된 축약형
    명령어 이름을 Alias라 한다.

    Alias는 "alias name=value" 형식으로 alias 명령어를 사용하여 생성한다.
    이때 name은 명령어 라인에 부여할 새로운 이름이며, value는 name을
    실행했을때 또는 호출했을때 실행할 하나 또는 그이상의 명령어가
    기술되어 있는 명령어 라인이다.

    또한 value에 공백이들어 있을 경우에는 명령어 라인 전체를 보호문자로
    묶어주어야 한다. 그러나 name에는 공백을 사용할 수 없으며, = 심볼
    전후에는 공백을 지정해서는 않된다.

    alias를 삭제하기 위해서는 unalias name의 형식으로 unalias 명령을 사용한다.

    alias를 사용함으써의 또다른 잇점은 쉘 프로그램보다 처리 속도가 빠르다는
    데 있다. 그러나 사용자가 너무나 많은 alias를 선언할 경우 쉘의 실행 속도가
    늦어지는 악영향을 초래한다. 그러므로 꼭 필요한 것만을 alias로 선언해야
    한다.

    alias 이름으로 기존의 명령어 이름을 지정할 수도 있다. 이와같이
    동일하게 사용되는 이름을 실행하면, 쉘이 alias의 지정된 명령어 라인으로의
    대치작업을 먼저 실행하기 때문에, alias로 지정된 명령어 라인을 실행한다.
    이 경우 alias가 아닌 기존의 명령어를 실행하기 위해서는 보호문자를
    통해 쉘의 대치 작업을 막아주어야 한다.

    그리고 alias 이름을 예약어와 동일하게 지정되었을 경우에는 쉘이 예약어에
    대한 처리를 alias 처리보다 먼저 행하기 때문에, alias는 무시되게 된다.

    만약 set -h 명령을 통해 쉘의 trackall 옵션이 설정되었을 경우, Korn Shell은
    명령어가 처음 실행되었을때, 명령어 이름에 대해 tracked alias를 정의한다.
    tracked alias는 명령어 실행을 빨리할 수 있도록 명령어를 alias로 선언하는
    기능이다. 정의되는 tracked alias 명으로는 절대 경로명이 사용된다.
    정의되어 있는 tracked alias는 alias -t 명령을 통해 표시할 수 있다.
    tracked alias는 PATH 변수가 reset될때 미정의되고, 명령어가 실행될때
    재구축된다.

    ( 예제 )
  ┌───────────────────────┐
  │KORN> alias ls='ls -CF'                       │
  │KORN> ls                                      │<- alias명인 ls가
  │bin/ f1 f2 f3 f4 f5 f6 f7 m1* m2* m3* m4*     │   실행되었다.
  │KORN> alias now="date;pwd;who am i"           │<- 하나의 alias에
  │KORN> now                                     │   여러 명령어가 지정된
  │Fri Aug 23 08:4233 EDT 1991                   │   예와 실행 결과
  │/home/mjr                                     │
  │mjr term/03    Aug 23 8:03                    │
  │KORN> unalias ls                              │<- alias를 제거한다.
  │KORN> ls                                      │<- ls 명령어가 실행된다.
  │bin f1 f2 f3 f4 f5 f6 f7 m1 m2 m3 m4          │
  └───────────────────────┘

5. 사전 정의된 alias들

    Korn Shell은 일반적으로 사용되는 명령어들을 축소한 일련의 alias를
    제공한다. 이러한 alias들은 사용자가 재정의할 수는 있으나, 될수 있는한
    재정의하지 않는다.

    다음은 사전 정의되는 alias들을 보여준다.

         ┌───────────┰─────────────┐
         │  사전 정의된 Alias   ┃      정의 내용           │
         ├───────────╂─────────────┤
         │     autoload         ┃    'typeset -fu'         │
         │     false            ┃    'let 0'               │
         │     functions        ┃    'typeset -f'          │
         │     hash             ┃    'alias -t -'          │
         │     history          ┃    'fc -l -'             │
         │     integer          ┃    'typeset -i'          │
         │     nohup            ┃    'nohup '              │
         │     r                ┃    'fc -e -'             │
         │     true             ┃    :                     │
         │    type              ┃    'whence -v'           │
         └───────────┸─────────────┘

    이상의 사전 정의된 alias중에 주목해야 할것이 있다.
    그것은 nohup alias의 정의에 들어있는 공백이다.
    이것은 Korn shell에게 nohup alias를 실행함에 있어서 alias 다음에
    사용자로 부터의 추가의 지정이 있다는 것을 알려줌으로써, Korn shell은
    alias 실행시 사용자에게 추가지정을 요구하게 한다.



'Academy I > Tech Academy' 카테고리의 다른 글

Unix 12 Shell Program Debugging I  (0) 2014.12.04
Unix 11 Regular Expression과 Filters: sort, tr  (0) 2014.12.04
Unix 10 Shell Program에서 쉘 특수 변수의 이용  (0) 2014.12.04
Unix 9 본쉘, 콘쉘  (0) 2014.12.04
Unix 7 프로세스, 쉘  (0) 2014.12.04
Unix 6 유틸리티  (0) 2014.12.04
Unix 5 통신,네트워크  (0) 2014.12.04
Unix 4 검색과 권한  (0) 2014.12.04