셸은 어떻게 명령을 실행할까?

연어코·2025년 11월 25일

기술 탐구

목록 보기
4/4
post-thumbnail

우리는 터미널을 열고 명령어를 입력합니다.

그럼 명령을 해석하는 프로그램인 셸(bash, zsh 등)은 어떻게 명령을 실행할까요?

<Operating Systems: Three Easy Pieces> 의 첫 번째 파트, Virtualization을 보며 내부 작동 원리를 알아봅시다.


1) The Abstraction: The Process

Intro

  1. 프로세스는 실행 중인 프로그램이다.

  2. 당신의 컴퓨터만 봐도 동시에 여러 개의 프로그램이 동시에 실행되는 것처럼 보인다. OS는 CPU를 가상화하여 이러한 환각을 일으킨다.

  3. CPU의 시간 공유(time sharing)로 알려진 이 기본 기술은 사용자가 원하는 만큼 동시에 프로세스를 실행할 수 있도록 한다.

...자세히 보기

Process API

  1. shell에 명령을 입력하거나 응용 프로그램 아이콘을 두 번 클릭하면 OS가 호출되어 지정한 프로그램을 실행하는 새 프로세스를 만든다.

  2. 많은 프로세스가 실행되고 완료되면 저절로 종료되지만, 그렇지 않을 때 사용자는 이를 죽이기를 원할 수 있으므로 폭주하는 프로세스를 중지하는 인터페이스가 매우 유용하다.

  3. 때로는 프로세스가 실행을 멈출 때까지 기다리는 것이 유용하다.

...자세히 보기

Process Creation: A Little More Detail

  1. OS가 프로그램을 실행하기 위해 가장 먼저 해야 할 일은 코드와 정적 데이터(예: 초기화된 변수)를 프로세스의 address space로 메모리에 로드하는 것이다.

  2. 무언가를 실행하기 전에 OS는 디스크에서 메모리로 중요한 프로그램 비트를 가져와야 한다.

  3. 코드와 정적 데이터를 메모리에 로드하고, 스택을 생성 및 초기화하고, I/O 설정과 관련된 다른 작업을 수행함으로써, OS는 이제 (마침내) 프로그램 실행을 위한 무대를 마련했다.

...자세히 보기

Process States

  1. 프로세스는 Running, Ready, Blocked의 세 가지 상태 중 하나에 있을 수 있다.

  2. ready에서 running으로 이동하는 것은 프로세스가 scheduled 되었음을 의미한다.

  3. 프로세스가 blocked 되면(예: I/O 작업을 시작함으로써) OS는 어떤 이벤트가 발생할 때까지(예: I/O 완료) 그대로 유지한다.

...자세히 보기

Data Structures

  1. OS는 프로그램이며, 다른 프로그램과 마찬가지로 다양한 관련 정보를 추적하는 몇 가지 주요 데이터 구조를 가지고 있다.

  2. 예를 들어, 각 프로세스의 상태를 추적하기 위해 OS는 ready 상태의 모든 프로세스에 대한 일종의 프로세스 목록과 현재 ready 상태인 프로세스를 추적하기 위한 몇 가지 추가 정보를 유지할 것이다.

  3. OS는 또한 어떤 식으로든 blocked 프로세스를 추적해야 한다. I/O 이벤트가 완료되면 OS는 올바른 프로세스를 깨우고 다시 실행할 수 있도록 준비해야 한다.

...자세히 보기

Interlude: Process API

The fork() System Call

  1. 프로세스는 OS가 새로운 프로세스를 생성하는 방법으로 제공하는 fork() system call을 호출한다.

  2. OS에는 이제 실행 중인 프로그램 p1의 두 복사본이 있는 것처럼 보이며, 둘 다 fork() system call에서 반환되려고 한다.

  3. 이제 자체 주소 공간(address space, 자체 개인 메모리), 자체 레지스터, 자체 PC 등을 가지고 있지만 fork() 호출자에게 반환되는 값은 다르다.

...자세히 보기

The wait() System Call

  1. 때때로 부모는 자식 프로세스가 해온 일을 끝내기를 기다리는 것이 매우 유용하다. (실무에서 각 프로세스의 작업 순서를 고정하고 싶을 때(결정적, deterministic) 유용하다.)

  2. 이 작업은 wait() system call (또는 더 완전한 형제 waitpid())로 수행된다.

  3. 부모 프로세스는 자식이 실행을 마칠 때까지 실행을 지연시키기 위해 wait()을 호출한다. 자식이 끝나면 wait()이 부모에게 반환된다.

...자세히 보기

Finally, The exec() System Call

  1. 종종 다른 프로그램을 실행하고 싶을 수 있는데, 이때 exec()를 쓰면 된다.

  2. exec() system call은 실행 파일(예: wc, 글자수 세기)의 이름과 일부 인수(예: p3.c)가 주어지면, 해당 실행 파일에서 코드(및 정적 데이터)를 로드하고 현재 코드 세그먼트(및 현재 정적 데이터)를 덮어쓴다.

  3. 따라서 그것은 새로운 프로세스를 만들지 않는다. 오히려 그것은 현재 실행 중인 프로그램(이전의 p3)을 다른 실행 중인 프로그램(wc)으로 변환한다.

...자세히 보기

Why? Motivating The API

  1. fork()와 exec()의 분리는 UNIX shell을 구축하는 데 필수적이다. 왜냐하면 fork() 호출 후 exec() 호출 전에 shell이 코드를 실행할 수 있기 때문이다.

  2. 대부분의 경우 shell은 파일 시스템에서 실행 파일이 있는 위치를 파악하여 fork()를 호출하여 명령을 실행할 새 자식 프로세스를 만들고 명령을 실행하기 위해 exec()의 일부 변형을 호출한 다음 wait()을 호출하여 명령이 완료될 때까지 기다린다.

  3. 자식이 완료되면, shell은 wait()에서 다시 돌아오고 프롬프트를 다시 출력하여 다음 명령을 준비한다.

...자세히 보기

Process Control And Users

  1. fork(), exec() 및 wait() 외에도 UNIX 시스템의 프로세스와 상호작용하기 위한 다른 많은 인터페이스가 있다.

  2. 예를 들어 kill() system call 호출은 일시 정지, 죽기 및 기타 유용한 명령어를 포함하여 프로세스에 signal을 보내는 데 사용된다.

  3. 편의를 위해 대부분의 UNIX shell에서 특정 키 입력 조합은 현재 실행 중인 프로세스에 특정 signal을 전달하도록 구성되어 있다. (예: control-c, control-z)

...자세히 보기

원문: https://product.kyobobook.co.kr/detail/S000001732370
PDF: https://pages.cs.wisc.edu/~remzi/OSTEP

profile
Invisible Treasure

0개의 댓글