ecole42

minishell

minishell은 ecole42의 프로젝트로, 명령어 실행, 파이핑, 리다이렉션, 환경 변수 관리, 시그널 처리 등 핵심 셸 기능을 제공하는 간소화된 셸 구현체. 셸이 저수준에서 어떻게 동작하는지 이해하기 위한 교육용 프로젝트로, 프로세스 관리, 파일 디스크립터 조작, 메모리 관리 등 시스템 프로그래밍 기술을 학습한다

C

개요

Minishell은 명령어 실행, 파이핑, 리다이렉션, 환경 변수 관리, 시그널 처리 등 핵심 셸 기능을 제공하는 간소화된 셸 구현체다. 셸이 저수준에서 어떻게 동작하는지 이해하기 위한 교육용 프로젝트다.

주요 기능

  • 명령어 실행: 내장 명령어와 외부 명령어 실행
  • 파이핑: 파이프(|)를 사용한 명령어 체이닝
  • 리다이렉션: 입력(<) 및 출력(>, >>) 리다이렉션
  • 환경 변수: 환경 변수 관리 및 확장 ($VAR)
  • 따옴표 처리: 작은따옴표, 큰따옴표, 이스케이프 시퀀스 지원
  • 시그널 처리: SIGINT (Ctrl+C) 및 SIGQUIT (Ctrl+) 적절한 처리
  • 명령어 구분: 세미콜론(;)을 사용한 명령어 분리 지원
  • 에러 처리: 포괄적인 에러 메시지 및 종료 코드

빌드 방법

사전 요구사항

  • GCC 컴파일러
  • Make
  • Unix 계열 운영체제 (macOS, Linux)

컴파일

# 저장소 클론
git clone [remote repository URL]

# 프로젝트 디렉토리로 이동
cd minishell

# 프로젝트 빌드
make

# minishell 실행
./minishell

Makefile 타겟

  • make 또는 make all: 프로젝트 컴파일
  • make clean: 오브젝트 파일 제거
  • make fclean: 오브젝트 파일 및 실행 파일 제거
  • make re: 프로젝트를 처음부터 다시 빌드

사용법

컴파일 후 ./minishell을 실행하여 셸을 시작한다. 다음과 같은 프롬프트가 표시된다:

MINISHELL$

이제 일반 셸처럼 명령어를 입력할 수 있다:

MINISHELL$ ls -la
MINISHELL$ echo "Hello, World!"
MINISHELL$ pwd
MINISHELL$ cd /path/to/directory
MINISHELL$ exit

내장 명령어

다음 명령어들은 내장 명령어로 구현되어 있다 (셸에서 직접 실행):

명령어설명예제
echo인자를 stdout에 출력echo hello world
cd디렉토리 변경cd /home/user
pwd현재 작업 디렉토리 출력pwd
export환경 변수 설정export VAR=value
unset환경 변수 제거unset VAR
env환경 변수 목록 표시env
exit셸 종료exit 또는 exit 42

지원 기능

파이핑

여러 명령어를 연결하여 실행:

MINISHELL$ ls | grep .c
MINISHELL$ cat file.txt | wc -l
MINISHELL$ echo "hello" | cat

리다이렉션

입력 리다이렉션 (<):

MINISHELL$ cat < file.txt

출력 리다이렉션 (>>>):

MINISHELL$ echo "hello" > output.txt
MINISHELL$ echo "world" >> output.txt

환경 변수

$VAR를 사용하여 환경 변수 확장:

MINISHELL$ echo $HOME
MINISHELL$ export MY_VAR=test
MINISHELL$ echo $MY_VAR

따옴표 처리

  • 작은따옴표: 리터럴 내용을 보존한다
  • 큰따옴표: 변수 확장을 허용한다
  • 이스케이프 시퀀스: 백슬래시(\)를 사용하여 특수 문자를 이스케이프한다

명령어 구분

한 줄에 여러 명령어 실행:

MINISHELL$ ls; pwd; echo done

시그널 처리

  • Ctrl+C (SIGINT): 현재 명령어를 중단하거나 프롬프트로 돌아간다
  • Ctrl+\ (SIGQUIT): 현재 명령어를 종료한다 (실행 중인 경우)

프로젝트 구조

minishell/
├── includes/
│   ├── minishell.h      # 함수 선언이 포함된 메인 헤더 파일
│   └── struct.h         # 데이터 구조 정의
├── srcs/
│   ├── main.c           # 진입점 및 메인 루프
│   ├── lexer_1.c        # 토큰화 (렉싱)
│   ├── lexer_2.c        # 렉서 헬퍼 함수
│   ├── parser_1.c       # 명령어 파싱
│   ├── init_cmd.c       # 명령어 리스트 초기화
│   ├── exec_command.c   # 명령어 실행 로직
│   ├── exec_*.c         # 내장 명령어 구현
│   ├── pipe.c           # 파이프 구현
│   ├── redirection.c    # I/O 리다이렉션
│   ├── dollar_quotes.c  # 변수 확장 및 따옴표 처리
│   ├── lst_*.c          # 연결 리스트 연산
│   ├── free_*.c         # 메모리 관리
│   └── error_*.c        # 에러 처리
├── lib/
│   └── libft/           # 커스텀 C 라이브러리 (문자열, 메모리 함수)
├── Makefile             # 빌드 설정
└── README.md            # 이 파일

주요 데이터 구조

  • t_minish: 메인 셸 상태 (명령어, 환경 변수, 토큰)
  • t_cmd: 명령어 구조 (인자, 파이프, 리다이렉션)
  • t_env: 환경 변수 연결 리스트
  • t_rdir: 리다이렉션 정보 (파일, 파일 디스크립터, 타입)

개발 워크플로우

1. 저장소 클론

git clone [remote repository URL]

2. 새 브랜치 생성

# 새 브랜치 생성 및 전환
git checkout -b [branch_name]

# 또는 두 단계로 수행
git branch [branch_name]
git checkout [branch_name]

3. 변경사항 커밋

# 모든 변경사항 스테이징
git add -A

# 설명이 포함된 커밋 메시지와 함께 커밋
git commit -m "[commit_message]"

# 원격 저장소에 푸시
git push -u origin [branch_name]

4. Pull Request 생성

GitHub에서 코드 리뷰를 위한 Pull Request를 생성한다.

5. 메인 브랜치와 동기화

변경사항이 병합된 후:

git checkout master
git pull origin master

참고 자료

리다이렉션과 파이프

  1. 셸 리다이렉션 마스터하기
  2. dup2() 예제

기술적 세부사항

  • 언어: C
  • 표준: C99
  • 컴파일 플래그: -Wall -Wextra -Werror
  • 메모리 관리: 수동 할당/해제
  • 프로세스 관리: fork(), execve(), wait(), waitpid()
  • 파일 디스크립터: dup(), dup2(), pipe(), open(), close()
  • 시그널: signal(), SIGINT, SIGQUIT

참고사항

  • 이 프로젝트는 교육용 프로젝트이며, 프로덕션 셸이 처리하는 모든 엣지 케이스를 처리하지 못할 수 있다
  • 일부 고급 셸 기능(작업 제어, 히스토리, 탭 완성 등)은 구현되지 않았다
  • 셸은 문자열 및 메모리 연산을 위해 커스텀 libft 라이브러리를 사용한다

작성자: wpark, froussel
프로젝트: 42 School minishell 프로젝트