- 입력 문자열을 인용 규칙을 준수하며 metacharacter 기준으로 단어 및 연산자, 즉 토큰으로 분해한다.
- 토큰을 Simple / Compound Command로 파싱한다.
- 셸 확장을 수행한다. 환경 변수 확장이 일어난다.
- 리디렉션을 수행하고 아규먼트 리스트에서 리디렉션 관련 연산자 및 피연산자를 제거한다.
- 명령을 실행한다.
- 명령이 종료되는 것을 대기한 후 exit status를 저장한다.
이때 metacharacter에는 space
, tab
, newline
, |
, <
, >
가 있다.
quoting이라 함은 홑따옴표나 쌍따옴표로 문자열의 특정 부분을 감싸는 것이다. 이때 metacharacter는 특별한 의미를 상실하게 되며 토큰으로 쪼개지지 않게 된다.
2개의 홑따옴표 사이에 온 문자들은 그 내용이 그대로 전달된다. 홑따옴표 쌍 사이에 홑따옴표 쌍이 겹쳐 있는 경우는 인정하지 않는다. 그러한 경우 2개의 겹치지 않은 쌍으로 해석한다.
이는 홑따옴표 인용과 동일하나 $
은 여전히 환경 변수를 확장한다는 의미를 가진다.
Simple Command는 <space>
로 구분되고 <newline>
으로 끝나는 단어들이다.
이때 첫 단어는 실행 파일의 이름이고 나머지는 매개 변수의 값이다. 이 명령의 exit status를 waitpid()
로 회수해야 한다.
|
로 연결된 simple command들이다. 각 simple command는 각자의 프로세스에서 실행되어야 한다.
마지막 simple command의 exit status가 pipeline의 status가 된다.
파라미터는 값을 담을 수 있는 어떤 것이다. 이때 값은 무언가의 이름일 수도 있고, 숫자 또는 특수문자일 수 있다.
변수는 이름이 붙은 파라미터이다. 하나의 값을 가지며 0개 이상의 속성을 가진다.
무언가에 값을 지정하면 파라미터가 생겨난다. 값 자체는 없어도 (NULL
) 무관하며, 빈 파라미터가 생성된다. 이는 unset
명령을 통해 없앨 수 있다.
파라미터에 지정되는 값은 저장되기 전 모두 셸 확장을 거친다.
$?
은 마지막으로 수행된 명령의 exit status를 담고 있다.
셸 확장이 일어나기 위해서는 기본적으로 다음과 같은 문법을 따라 문자열이 등장해야 한다. ${parameter}
이때 parameter가 한자릿수 이상의 숫자거나 (위치 파라미터) parameter 뒤에 문자가 올 시 {}
가 필요하다.
here-document의 기본 문법은 다음과 같다.
<< word
here-document
delimeter
이때 word
에 대해서 파라미터 확장은 일어나지 않는다. 다만 따옴표가 남아있을 시 이들은 제거된다.
delimeter
는 앞 뒤에 공백 없이 word
와 완전히 일치할 경우 인정된다.
word
에 따옴표가 있을 시 here-document
내용은 확장되지 않는다. 반대의 경우 확장이 일어난다.
Simple Command를 실행하려면 확장, 리디렉션을 수행해야 한다. 커맨드는 왼쪽에서 오른쪽으로 토큰을 읽으며 차례대로 실행한다. 자세한 방법은 다음과 같다.
- 리디렉션 관련 단어일 경우 추후 처리할 수 있게 저장해 놓는다.
- 위에 해당하지 않는 단어는 확장을 거친다. 결과가 1개 이상 단어일 시 첫 단어가 명령 이름, 나머지는 매개변수다.
리디렉션만 하는 명령어는 셸 환경 변수를 조작할 수 있다. 그렇지 않고 다른 행동까지 포함하는 명령어에서 지정된 변수는 해당 명령에서만 사용 가능하다.
이것은 전자는 본래 프로세스에서 실행되는 명령이지만 후자는
fork()
된 새 프로세스에서 실행되기 때문이다.
- 명령어에 슬래시가 없을 시 실행 파일의 실제 위치를 찾으려 시도한다.
- 빌트인 명령어의 이름과 일치할 시 이를 실행한다.
- 일치하지 않는데 슬래시가 없을 시
$PATH
에서 그 실행 파일이 있는 디렉토리를 찾으려 한다. 없을 시 코드 127 반환 - 실행 파일을 찾았거나 이름에 슬래시가 있을 시 별도의 환경에서 실행한다. 이때 아규먼트 0번은 파일의 이름, 나머지는 simple command의 나머지 단어들을 순서대로 입력한다.
- 파일을 실행할수 없고, 파일이 디렉토리가 아닐 시, 셸 스크립트로 간주하여 실행한다.
- 명령이 실행되는 것을 기다리고 종료 코드를 회수한다.
프로그램이 실행될 때 프로그램이 열어 놓은 파일이나 현재 디렉토리 등을 프로그램의 환경이라고 한다. 빌트인이 아닌 simple command가 실행될 시 다음 환경 요소들을 그대로 복제한 새 환경에서 실행된다.
- 열린 파일 (fd table)
- 현재 디렉토리 (CWD)
- 파일 생성 모드 마스크 (umask)
- export 속성이 켜져 있는 변수 및 커맨드 실행 시 export된 변수
subshell이란 원본 셸의 복사본이다. 명령 탐색을 통해 실행된 명령, 파이프라인 내에서 실행된 빌트인 명령은 subshell에서 실행된다.
환경은 "이름=값"의 쌍으로 구성된 문자열이다. C 언어에서는 getenv
및 char** envp
변수를 통해 접근할 수 있다. 셸이 실행 시 찾아낸 모든 이름들에 대해 export 속성을 켠 채로 파라미터를 생성한다.
커맨드를 실행할 시 기본적으로 환경은 유지된다. 외부 명령을 실행하기 전 $_
변수를 해당 명령의 절대경로 (full pathname)으로 설정해야한다.
Exit Status는 0 이상 256 미만 값을 가진다. 이 중 125를 초과하는 값은 셸이 특별한 의미로 사용한다.
- 0: 성공
- 128 + N: 치명적 신호 N번에 의해 종료됨
- 127: 커맨드를 찾지 못함
- 126: 커맨드를 찾았지만 실행할 수 없음
- 양수: 명령 이름을 찾거나 리디섹션을 하던 중 오류 발생
마지막으로 실행된 명령의 Exit status는 $?
에 저장된다.
- Interactive 모드에서는
SIGTERM
을 무시한다. SIGINT
는 새 프롬프트를 띄우거나 빌트인 명령을 중지시키는 등 적절히 처리한다.- 항상
SIGQUIT
는 무시한다. SIGHUP
을 받을 시 셸이 종료된다.- 빌트인이 아닌 명령은 부모 셸에서 시그널 핸들러를 상속받는다.
명령이 실행되는 중 생성된 키보드 시그널은 셸에게도 전달된다. 이것은 셸과 셸이 생성한 명령 프로세스는 같은 프로세스 그룹에 속해있기 때문이다. SIGINT
를 받았다면 명령이 끝나기를 기다린 후 새 프롬프트를 띄우면 된다.
Ctrl+C
→SIGINT
Ctrl+\
→SIGQUIT
Ctrl+D
→EOF
전달
셸을 실행할 시 첫 아규먼트로 파일 이름을 넣으면 해당 파일을 읽어 실행하게 된다. 이때 $0
은 파일의 이름, $1
…$N
은 나머지 아규먼트가 된다.
셸이 명령 이름 탐색을 수행할 때 이름이 일치하고 실행 비트(chmod)가 켜진 스크립트 파일을 찾을 시 실행하려고 시도하게 된다. 즉 셸에 ./script arguments
라고 입력하는 것은 minishell ./script argument
와 같다.
스크립트의 첫 줄에 #!
가 있을 시 Shebang 절차에 의거 해당 파일을 해석할 프로그램을 찾아 넘긴다.
echo [-n] [args …]
args
들을 <space>
로 구분하고 <newline>
을 끝으로 출력한다. 이때 -n
옵션이 켜졌을 경우 끝에 <newline>
을 출력하지 않는다.
exit status는 쓰기 오류가 없는 한 0이다.
cd [dir]
dir
로 현재 디렉터리 (Current Working Directory)를 바꾼다. dir
가 제공되지 않을 시 $HOME
의 값으로 변경한다.
..
는 상위 디렉터리, -
는 $OLDPWD
의 값으로 변경한다. -
를 사용했다면 STDOUT에 새 pwd의 절대경로를 출력한다.
cd
가 성공했다면 $PWD
에 새 pwd를, $OLDPWD
에 이전 pwd를 저장한다.
exit status는 성공시 0, 실패시 0이 아닌 값이다.
pwd
현재 디렉토리를 STDOUT에 출력한다. exit status는 성공시 0, 실패할 경우 0이 아닌 값이다.
export [name[=value] ...]
name
이 제공되지 않을 시 현재 export된 모든 변수를 표시한다. name
이 제공될 시 해당 변수의 export
속성을 켠다. =value
가 제공될 시 해당 name
에 값을 할당한다.
올바르지 않은 옵션을 입력하거나 올바르지 않은 name
이 입력될 시 0이 아닌 값을, 그렇지 않을 경우 0을 반환한다.
declare -x NAME="VALUE"
unset [name ...]
각 name
를 변수에서 삭제한다. 제거에 성공시 0, 실패할 시 0이 아닌 값을 반환한다.
env
환경 변수의 목록을 출력한다.
성공시 0, 실패시 양수를 반환한다.
exit [n]
n
을 exit status로 셸을 종료한다. n
이 제공되지 않을 시 마지막 실행된 명령의 status가 반환된다.