0. 프로젝트 목표
- bash와 기능이 유사한 minishell 만들기
- 문자열 분석, 프로세스, 파일 디스크립터 관리가 주를 이룸
- 즉, 파싱, 포크, 파이프에 대해 중점적으로 학습하고 작성해야 함
- 또한 구조적으로 잘 잡아야지 클린한 데이터를 계속들고 다니면서 코딩할 수 있음
1. 학습
우선 키워드 정리하고 함수에 대한 정리가 필요
2. 구조잡기
큰 틀
1. 데이터 초기화 (환경변수, 들고다닐 데이터변수)
2. 프롬프트 찍기
3. while문 실행
-> 문자열 읽기
-> 파싱하여 토큰화 하기
-> 파싱한 데이터 검사하기
-> 토큰화한 데이터로 실행시키기
파싱단계
%%% 따옴표는 현재 line에 i번째가 쌍따옴표 안인지 밖인지, 홑따옴표 안인지 밖인지에 대한 함수를 만들어서 편했음 %%%
1. EOF아닐 때 까지 한 줄 읽기
2. 따옴표안쪽이 아닌 스페이스로 구분하기
3. 쌍따옴표 안에서 이스케이프로 작동한 \ 제거하기
4. 이스케이프된 문자는 음수로 바꿔놓기 (음수는 ?로 표시함)
5. $는 이러한 과정을 한번 더함, 홑따옴표에서 $가 쓰이면 이스케이프된 문자로 생각해서 음수로 바꿔놓기
-> echo "Hello ? ? $A" $A '?A\\\' >> tmp1 > tmp2 ; echo asdf | grep d
6. 이러한 것을 스페이스 단위로 토큰화 하기
7. 위치를 기반으로 토큰의 타입정하기 (CMD, ARG, OUTPUT, INPUT, PIPE....)
실행단계
%%% CMD토큰타입만 찾아서 실행함, 또한 CMD단위의 구분은 |나 ;나 끝이 구분함 %%%
1. 현재 CMD가 가지는 블록의 토큰들을 깨끗하게 바꿔줌
-> $VAL을 환경변수에서 찾아 문자열로 치환해서 넣어줌
-> 따옴표 제거
-> 음수로 처리했던 이스케이프 문자를 다시 양수로 토글함
2. 현재 CMD블록의 이전 파이프가 있으면 dup2함 -> 하자마자 일반 fd를 close함
3. 현재 CMD블록의 이후 파이프가 있으면 dup2함 -> 하자마자 일반 fd를 close함
4. 현재 CMD블록 근처의 redirection을 처리함 -> open -> dup2 -> close
-> 2,3,4단계로 STDOUT, STDIN의 가르키는 파일이 바뀌었을 것
5. cmd를 만들어줌 -> CMD하나와 ARGS들을 char **로 만들어줌
6. exec함 (execve할 때는 fork해서 처리함)
3. 나의 minishell 구현정도
대부분 bash와 동일, 다른 부분은 아래와 같음
역슬래쉬는 쌍따옴표 안에만 작동, 밖에 있으면 에러 처리
-> ex) echo \""" X
-> ex) echo "\"" O
어느 한 블록에 cmd가 없으면 에러처리함
-> ex) > file.txt
시그널에서 입력중일 때 + Ctrl + \ + 이후에 입력하면 이후에 것만 남아있음에 유의
-> ex) echo^\ ls -> ls 실행
$? (exit_code)
-> a$? | b$? | c$? 같은 경우 구현하지 않음
-> 0 1 127 126 258 130 131 정도만 구현
0 : success
1 : file not found
127 : cmd not found
126 : is dir
258 : syntax error
130 : child int
131 : child quit
~ 구현하지 않음 (~은 순수한 절대경로, 상대경로가 아님)
builtin과 실행파일은 다름에 주의
-> unset PATH를 했다하더라도 echo 같은 명령어를 builtin으로 구성했기 때문에 실행이 되어야 함
4. 힘들거나 어려웠던 점
1. 프로세스와 파일디스크립터에 대한 이해가 부족하여 서브젝트에 대한 감도 못잡음
2. 이해했으나 어디에 사용하는지 모름
3. 문자열 분석, 파싱부터 하려하는데, 쌍따옴표, 홑따옴표, 이스케이프, $에 대한 예외가 너무 많았음
4. 분업의 어려움 -> "난 파싱할테니 넌 실행해" 이런식의 분담을 하려면 옆에 딱 붙어 있어야 할 듯
5. bash와 유사도를 높이려다 기존의 코드가 망가지는 일이 발생하여 복잡해짐
6. 구현에 힘쓰다가 내 코드를 동료분이 읽기가 힘들어짐 (놈과 관련이 크긴 함)
7. 몸이 아프면 그냥 힘듦
8. fork()를 언제 해야할까, close()를 언제 해야할까, pipe()를 언제 해야할까에 대한 의문
-> 이 구조를 짜는게 가장 어려웠는데
-> 간단한 test_main.c을 만들어서 하나씩 해봄
-> fork는 exec하기전에 하면 됨
-> close는 dup2하면 close당기면 됨
-> pipe는 CMD블록에서 다음파이프토큰이 있으면 pipe 생성 해놓으면 됨
'42cursus' 카테고리의 다른 글
philosophers[철학자] - 룰 그리고 쓰레드, 뮤텍스, 세마포어, 프로세스 (0) | 2021.02.26 |
---|---|
philosophers[철학자] - 외부함수 정리하기 (시간, 쓰레드, 뮤텍스, 세마포어) (0) | 2021.02.25 |
minishell - 명령어와 외부함수 정리하기 (command & External functions, 42seoul) (0) | 2021.01.25 |
ft_services - 가이드 및 참고자료 정리하기 (42seoul) (0) | 2021.01.07 |
Kubernetes(쿠버네티스) 개념 정리하기 (0) | 2021.01.07 |