minishell(1) - 쉘 스크립트 공부하기

yeham·2023년 4월 22일
0

42Seoul

목록 보기
14/18
post-thumbnail

minishell 프로젝트는 셸 스크립트 중 하나인 bash를 구현하는 프로젝트입니다.
그러나 이름에서 유추할 수 있듯 세부적인 동작까진 무리이고 manual을 참고하여 작성합니다.

Shell 이란?

명령어 처리기 (ex. 터미널)
쉘은 운영 체제 상에서 다양한 운영 체제 기능과 서비스를 구현하는 인터페이스를 제공하는 프로그램입니다. 즉, 사람이 컴퓨터에게 어떤 일을 시킬 때 쓰는 프로그램 정도로 이해하면 될 것 같습니다.
종류로는 bash, zbash, ksh, csh 등이 있습니다.

BASH란?

GNU 프로젝트의 일부로, Bourne shell을 대체하기 위해 만들어진 Unix 계열 운영체제용 POSIX shell.
거의 모든 리눅스 배포판에 기본 로그인 shell로 깔려있다. 그래서 보통 shell scripting이라고 하면 Bash를 의미합니다.
스크립팅 언어답게 인터프리터로 돌아가며, C로 개발되었습니다.

Bash Reference Manual
The Open Group Base Specifications Issue 7, 2018 edition

두 사이트의 매뉴얼을 참고하여 프로그램을 작성하였습니다.

minishell의 동작을 크게 4가지로 파트를 나눌 수 있습니다.

parsing / exec / built_in / signal

  • parsing : 문자열로 받은 입력을 가장 작은 단위인 토큰 단위로 먼저 나누고 원하는 형태에 맞게 가공해는 작업입니다.
    '(싱글 쿼트), "(더블 쿼트), 공백, '$'(환경 변수)부터 해서, '|'(파이프라인), '<, >'(리다이렉션), '<<, >>' (heredoc)

  • exec : 실행 부분으로 parsing 단계에서 가공된 문자들을 해당 파트에서 동작시킵니다. 이때 맨 처음 들어온 명령어와 파이프의 유무에 따른 fork로 프로세스 생성 및 병렬처리 등을 진행합니다

  • built_in : PATH 디렉토리 안에 해당하는 명령어가 없을 경우 직접 구현하는 부분입니다. 예를 들어 export, unset, exit과 같은 명령어들은 해당 디렉토리에 없기 때문에 exec에서 실행이 불가능합니다.

  • signal : ctrl + c, ctrl + d, ctrl + \ 과 같은 시그널 처리들을 구현합니다. 특히나 erron 리턴 값을 유의하며 코드를 작성해야 합니다.

큰 동작은 위 Mermaid 플로우차트와 같습니다.

그 외 필요한 세팅

brew

  • brew 설치
    rm -rf $HOME/.brew && git clone --depth=1 https://github.com/Homebrew/brew $HOME/.brew && export PATH=$HOME/.brew/bin:$PATH && brew update && echo "export PATH=$HOME/.brew/bin:$PATH" >> ~/.zshrc
  • readline 함수를 사용할 때 필요하다.
  • readline 설치
    //설치
    brew install readline
    //업데이트
    brew link --force readline
  • bash 설치
    //설치
    brew install bash
    //업데이트
    brew link --force bash

시그널(signal)

  • 동기(synchronous), 비동기(asynchronous)

동기적 처리 : 순서대로 진행하는 것, 지금 진행하는 것이 종료되고 다음 작업으로 넘어감

비동기적 처리 : 순서대로가 아니라 한 번에 여러 개가 진행되는 것

  • 소프트웨어 인터럽트로, 프로세스에 무엇인가 발생했음을 알리는 간단한 메시지를 비동기적으로 보내는 것

프로세스 레벨에서 처리되고, pcb 블록에서 특정 변수에 비트 마스킹이 돼서 저장되는데 이는 프로세스 스케줄링을 할 때 확인을 해서 바로 실행된다.

예) kill 함수를 통해 특정 프로세스에게 시그널을 보낸다. Ctrl + c를 눌러서 프로세스를 끝내기

Struct stat

  • 파일 정보를 저장하는 구조체
  • inode
    • 파일을 기술하는 디스크 상의 데이터 구조
    • 파일의 데이터 블록이 디스크 상의 어느 주소에 위치하고 있는가와 같은 파일에 대한 중요한 정보를 가지고 있다.
    • 저장되는 정보들
      • 파일의 소유권(사용자, 그룹)
      • 파일의 권한
      • 파일의 타임스탬프(파일의 마지막 수정, 액세스..)
      • 파일의 종류
  • 저장하는 내용들 - _DARWIN_FEATURE_64_BIT_INODE이 정의 유무에 따라서 다르게 정의된다.

IEEE

  • Institute of Electrical and Electronics Engineers, IEEE
  • 산업 기간의 표준화를 구현한다.

POSIX

  • Portable Operating System Interface → 다른 운영체제들 사이의 호환성을 위해 IEEE에서 만든 표준
  • 그래서, POSIX 표준을 지키는 운영체제는 다른 운영체제로 쉽게 호환이 가능하다. 예) Solaris, macOS

API

  • Application Programming Interface → 두 소프트웨어 구성 요소가 서로 통신할 수 있게 하는 메커니즘

    예) 기상청 소프트웨어 시스템에는 기상 데이터가 있다. 휴대폰의 날씨 앱은 API를 통해 이 시스템과 대화하여
    휴대폰에 매일 최신 날씨 정보를 표시한다.

struct termios

  • POSIX가 지정하는 표준 인터페이스

  • 값을 설정함으로써 인터페이스 제어

  • 5가지 모드(입력, 출력, 제어, 로컬, 특수 제어문자)로 분류 가능

  • c_lflag의 속성

    비트 마스킹으로 플래그를 지정한다.
    ISIG : signal(ctrl + c(sigint), ctrl + z(sigstp)….)를 받아들인다.
    ICANON : 정규모드로 입력을 받는다.
    ECHO : 반향을 설정한다.

    struct sigaction

  • sa_flags는 아래와 같은 값이 사용되며 OR 연산자로 여러 개를 지정하여 사용할 수 있다.

struct sigaction

  • sa_flags는 아래와 같은 값이 사용되며 OR 연산자로 여러 개를 지정하여 사용할 수 있다.
옵션의미
SA_NOCLDSTOPsignum이 SIGCHLD일 경우, 자식 프로세스가 있을 경우에만 SIGCHLD를 보낸다. 자식 프로세스가 멈췄을 경우에는 보내지 않는다.
SA_ONESHOT SA_RESETHAND시그널을 받으면 설정된 sa_handler를 실행하고, 시스템 기본 설정인 SIG_DFL로 설정된다.
SA_RESTART시그널 처리에 의해 방해 받은 시스템 호출은 시그널 처리가 끝나면 재시작한다.
SA_SIGINFO이 옵션이 사용되면 sa_handler 대신에 sa_sigaction이 동작되며, sa_handler 보다 더 다양한 인수를 받을 수 있다. sa_sigaction이 받는 인수에는 시그널 번호, 시그널이 만들어진 이유, 시그널을 받는 프로세스의 정보입니다.
struct sigaction
{
	void (*sa_handler)(int); //시그널을 처리하기 위한 핸들러
													 //SIG_DFS, SIG_IGN 또는 핸들러 함수
	void (*sa_sigaction)(int, siginfo_t *, void *); //밑의 sa_flags가 SA_SIGINFO일 때
																									//sa_handler 대신에 동작하는 핸들러
	sigset_t sa_mask; //시그널을 처리하는 동안 블록화할 시그널 집합의 마스크
	int      sa_flags; //아래 설명 참고
	void (*sa_restorer)(void); //사용해서는 안 된다.
}

struct sigaction
{
	union	__sigaction_u __sigaction_u; /* signal handler */
	sigset_t	sa_mask; /* signal mask to apply */
	int			sa_flags; /* see signal options below */
}

union __sigaction_u
{
	void	(*__sa_handler)(int);
	void	(*__sa_sigaction)(int, siginfo_t *, void *);
};
profile
정통과 / 정처기 & 정통기 / 42seoul 7기 Cardet / 임베디드 SW 개발자

0개의 댓글