쉘(Shell)

신준우·2023년 5월 31일
0

시스템 프로그래밍

목록 보기
3/12

쉘이란?

  • OS의 기능들을 사용할수 있게 연결해주는 user interface
  • 대부분 command-line interface(CLI)를 사용한다
  • 프로세스를 관리하고 다른 프로그램들을 구동시키는 프로그램
  • 다양한 쉘이 Linux/Unix에서 사용된다 ex) sh, bash, tcsh, csh, zsh...etc
  • 세가지 주요 기능이 있다.
    - 프로그램 실행
    - 입/출력 관리
    - 사용자가 직접적으로 프로그래밍 가능한 ui

    리눅스 터미널도 쉘의 한 종류라고 볼 수 있다. 프로세스를 관리할수 있고, OS의 기능을 사용할수 있게, 유저(USER) 친화적이며, CLI를 사용한다. 무엇보다, 윈도우에서의 터미널에 해당하는 Power-Shell을 생각해보자, 이름부터 쉘이다.

쉘의 주요 기능

- 프로그램 가동

  • 쉘은 사용자의 명령을 해석하고, 관련된 프로그램을 메모리에 로드하고 실행하는 역할을 한다
    - "프로그램 런처(program launcher)"라고 생각해도 편하다

- 입출력 관리

  • '>', '<', '|' : input/output의 리다이렉션(redirection)
    ※ 리다이렉션 (Redirection): 입력값, 출력값이 기본값이 아닌 다른 파일들을 향하도록 지시해주는것

  • 위의 기호들을 사용하여 유저(user)는 쉘에게 input/output 프로세스를 사용할지 말지 전달해준다

- 프로그래밍

  • 변수와 흐름 제어를 가진 "프로그래밍 언어"
    - 쉘에 코드를 입력하면 커맨드가 자동화된 방식으로 실행될것이다

    	이런식으로!
    	상세한 명령어들, (do, echo, done 등등)은 몰라도 괜찮다! 이런 기능이 있다고 생각하자!

쉘은 프로그램을 어떻게 굴릴까?

  • 쉘은 프롬프트를 출력한다
  1. 커맨드를 입력하면?
  2. 쉘은 커맨드를 시행한다
  3. 쉘은 프롬프트를 계속해서 출력해낸다

실제 컴퓨터에서는 어떤 일이 일어나고 있는걸까?

  • 예시를 한번 살펴보자.

A. 유저가 'a.out'을 입력한다
B. 쉘이 프로그램을 굴리기 위한 새로운 프로세스를 생성한다
C. 쉘이 디스크에 있는 프로그램을 프로세스로 로드한다
D. 프로그램이 작업을 마칠때까지 프로세스에서 동작한다

쉘의 Main Loop

while( ! end_of_input){
	get command
    execute command
    wait for command to finish
}

자, 이게 무슨소리인가 싶을거다. 잘 생각해보자. 우리가 리눅스에서 가장 많이 사용하는 쉘인 터미널을 생각해보자

터미널은은 계속해서 입력을 받는다, 그러므로 end_of_input이 입력되기 전까지 무한 반복,

  • get command를 통해 command를 입력받음
  • execute command를 통해 종료하는 command를 입력받기도 하고,
  • wait for command to finish를 통해 get command를 입력받은 프로세스가 종료되길 기다린다

이제 쉘의 main loop가 저렇게 생긴 이유가 이해되었 을것이다

위의 그림을 보고, 다시 이해해보자

  • 쉘을 작성하기 위해서
    1. 프로그램을 굴린다
    1. 프로세스를 생성한다
    2. exit()가 호출되길 기다린다

일단 이것들에 좀 더 익숙해지면, 스스로의 쉘을 만들어 낼 수 있을것이다!

프로그램은 어떻게 프로그램을 실행시킬까?

프로그램은 execvp()함수를 통해서 실행된다

execvp()
PURPOSE 경로를 탐색해서 파일을 실행시킨다
INCLUDE #include <unistd.h>
USAGE result = execvp(const char file, const char argv[])
ARGS file: name of file to execute, argv: array of strings
RETURNS -1 if error

자, 표로 간단하게 정리하긴 했지만, 다시 코드로, 구어체로 설명하며 이해해보자

일단

  • unistd.h 헤더에 정의된 함수이다
  • 사용방법은 결과값 = execvp(파일이름, 문자열)
  • 에러가 발생할시 result, 즉 '결과값'에 -1이 반환된다

그럼, execvp의 작동 과정을 알아보자

  1. '파일이름'값에 지정된 이름의 프로그램을 복사하여 execvp의 호출 프로세스에 전달한다
  2. 지정된 문자열 목록을 argv[] 로 전달한다
  3. 프로그램을 실행시킨다

대충 이런 과정을 통해 작동하게된다. 그러나 와닿지 않는 설명들이 많다. 이후 직접 코드를 짜서 분석하면서 이해해보자.

exec1.c

//exec1.c
//purpose : 프로그램이 다른 프로그램을 실행시키기 얼마나 쉬운지 보여주기 위함


#include <unistd.h>
#include <stdio.h>

int main(int argc, char* argv[])		// argc: 명령어로 전달되는 인자의 개수
									// argv: main()에 실질적으로 전달되는 데이터,
                                    // 문자열의 배열을 의미한다.
{
	char arglist[3];		// 크기 3짜리 문자열 리스트, 이름은 arglist
    arglist[0] = "ls";		// 첫번째 칸은 "ls" 실행할 프로그램의 경로를 나타냄
    arglist[1] = "-l";		// 두번째 칸은 "-l" ls명령어에 전달할 옵션
    arglist[2] = 0;			// 세번째 칸은 "0" 배열의 끝 표시
    
    printf("*** About to exec 'ls -l' \n");		// 실행할 명령어를 나타내는 메세지,
    											// 여기선 ls -l을 실행합니다~ 라고 표시
    execvp("ls", arglist);		// execvp함수를 호출하여 ls실행
    							// arglist에 포함된 인자들 전달
    printf("*** ls is done. Bye\n");	// 프로그램종료, 안녕~!
}

결국 이 코드는 execvp함수를 사용하면, 프로그램을 프로세스에 할당하는게 얼마나 쉬운지 보여주기 위함이다

이제 무슨 일이 벌어지는지 살펴보자,

  1. 커널이 새 프로그램을 현재 프로세스에 로딩한다.
    이때, 현재 프로세스에 실행중이던 코드와 데이터는 새 프로그램으로 대체된다.
  2. exec 시스템 호출:
    • execvp란?
      - execvp는 C프로그래밍 언어에서 사용되는 라이브러리 함수 중 하나이다.
      - 실행 파일을 실행하는 기능 제공
      - execve 시스템 호출을 사용해서 실행파일을 생성하게 됨
    • 프로세스를 클리어하고 새로운 프로세스를 로딩시킨다
  3. 프로세스의 메모리 위치는 프로그램이 요규하는 공간에 맞게 바뀐다
    • 프로세스는 같지만 그 안의 컨텐츠는 새로운 컨텐츠이다

이 쯤에서 슬슬 머리가 어질어질하다.
원래 우리가 배우려 했던 학습목표가 뭐였는지 다시 알아보고 공부를 시작해보자

profile
보안

0개의 댓글