Minishell

이 프로젝트는 리눅스의 대표적인 쉘인 Bash를 C언어로 구현하는 프로젝트이다. 리눅스의 프로세스 관리, FD, 시그널 등 시스템 프로그래밍의 핵심적인 개념들을 학습하고 구현하였다.

주요 구현 기능

  1. 명령어 해석
  2. Built-in 명령어
  3. 바이너리가 있는 명령어
  4. 다중파이프와 리다이렉션
  5. 시그널 처리

프로젝트 구조

minishell/
├── include/
│   ├── minishell.h    # 메인 헤더 파일
│   ├── exec.h          # 실행 관련 함수 정의
│   ├── parse.h         # 파싱 관련 함수 정의
│   └── Libft/          # 유틸리티 라이브러리
├── srcs/
│   ├── exec/           # 명령어 실행 로직
│   └── parse/          # 입력 파싱 로직
└── main.c              # 메인 루프

명령어 해석

Bash에 입력된 명령어의 해석에 대한 순서를 먼저 정하였다. 우리는 이에 대해 다음과 같은 순서로 정의했다.

  1. 파이프 단위로 입력된 명령어를 분리한다.
  2. 한 단위의 명령어에서 가장 먼저 리다이렉션 문자를 탐색한다.
  3. 리다이렉션 문자가 있다면 파일디스크립터를 적절히 연결한다.
  4. 명령어를 찾아 실행한다.

입력된 명령어를 해석하는 알고리즘은 함께했던 팀원이 작성하였다. 다만, 이 해석된 자료를 어떤 식으로 실행함수로 넘길 것인지에 대해 함께 논의했고, 적절한 방향으로 구현하였다.

Built-in 명령어

Bash의 명령어는 두 종류로 나뉘어 있다고 판단하였다. Built-in 명령어는 여러 /bin 디렉토리에 바이너리가 존재하지 않는 명령어이다. 이 명령어들은 /bin 디렉토리를 포함하는 모든 환경변수를 제거하여도 동작한다. 따라서, 해석된 명령어를 환경변수에서 찾아 실행하기 전에 우선적으로 실행하여야 한다. 성공적으로 실행하면 다시 루프로 돌아가고, 실패했다면 환경변수에 등록된 바이너리 파일을 찾기 위한 함수가 실행된다.

바이너리가 있는 명령어

이 명령어들은 해석된 명령어가 Built-in이 아닐 때 실행된다. 이를 위해 $PATH 환경변수에 등록된 모든 경로를 탐색한다. 일치하는 명령어를 찾지 못했을 경우 관련 로그를 출력하고, 다시 루프로 돌아간다.

다중파이프와 리다이렉션

명령어 해석단계에서 전체 명령어는 파이프 단위로 분리되어 연결리스트에 저장된다. 문자열 형태로 저장된 명령어를 탐색하여 리다이렉션 문자를 먼저 탐색한다. 리다이렉션 문법에 맞지 않거나 실행 불가능한 명령일 경우 에러 로그를 출력하고 루프로 돌아간다. 또한, 파이프로 분리된 명령어절은 각각 한 개의 자식 프로세스를 생성하여 실행되며, 파이프로 연결된 입력과 출력은 파일 디스크립터를 통해 통제된다. 따라서 입력된 전체 명령어는 순서대로 실행되는 것이 아니라, 각각이 동시에 실행되는 것에 가깝다. 모든 명령어가 실행되거나 종료되면 다시 루프로 돌아간다.

시그널 처리

과제를 처음 진행할때는 종료코드와 시그널간의 혼동이 있었다. 종료코드는 echo $? 등을 통해 확인할 수 있다. 명령어나 프로그램이 종료될때 메인 프로세스에게 보내는 코드로, 이 코드를 통해 어떠한 상태로 종료 되었는지 확인할 수 있다.
시그널은 사용자가 쉘에 입력하는 신호이다. 쉘 프로그램은 이 시그널을 감지하여 프로그램이 실행중에도 다른 동작을 할 수 있도록 되어있으며, 관련 함수를 통해 구현된다.

https://github.com/grademe12/miniShell

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다