리눅스 터미널도 쉘의 한 종류라고 볼 수 있다. 프로세스를 관리할수 있고, OS의 기능을 사용할수 있게, 유저(USER) 친화적이며, CLI를 사용한다. 무엇보다, 윈도우에서의 터미널에 해당하는 Power-Shell을 생각해보자, 이름부터 쉘이다.
'>', '<', '|' : input/output의 리다이렉션(redirection)
※ 리다이렉션 (Redirection): 입력값, 출력값이 기본값이 아닌 다른 파일들을 향하도록 지시해주는것
위의 기호들을 사용하여 유저(user)는 쉘에게 input/output 프로세스를 사용할지 말지 전달해준다
변수와 흐름 제어를 가진 "프로그래밍 언어"
- 쉘에 코드를 입력하면 커맨드가 자동화된 방식으로 실행될것이다
이런식으로!
상세한 명령어들, (do, echo, done 등등)은 몰라도 괜찮다! 이런 기능이 있다고 생각하자!
A. 유저가 'a.out'을 입력한다
B. 쉘이 프로그램을 굴리기 위한 새로운 프로세스를 생성한다
C. 쉘이 디스크에 있는 프로그램을 프로세스로 로드한다
D. 프로그램이 작업을 마칠때까지 프로세스에서 동작한다
while( ! end_of_input){
get command
execute command
wait for command to finish
}
자, 이게 무슨소리인가 싶을거다. 잘 생각해보자. 우리가 리눅스에서 가장 많이 사용하는 쉘인 터미널을 생각해보자
터미널은은 계속해서 입력을 받는다, 그러므로 end_of_input이 입력되기 전까지 무한 반복,
- get command를 통해 command를 입력받음
- execute command를 통해 종료하는 command를 입력받기도 하고,
- wait for command to finish를 통해 get command를 입력받은 프로세스가 종료되길 기다린다
이제 쉘의 main loop가 저렇게 생긴 이유가 이해되었 을것이다
위의 그림을 보고, 다시 이해해보자
execvp() |
---|
PURPOSE 경로를 탐색해서 파일을 실행시킨다 |
INCLUDE #include <unistd.h> |
USAGE result = execvp(const char file, const char argv[]) |
ARGS file: name of file to execute, argv: array of strings |
RETURNS -1 if error |
자, 표로 간단하게 정리하긴 했지만, 다시 코드로, 구어체로 설명하며 이해해보자
일단
대충 이런 과정을 통해 작동하게된다. 그러나 와닿지 않는 설명들이 많다. 이후 직접 코드를 짜서 분석하면서 이해해보자.
//exec1.c
//purpose : 프로그램이 다른 프로그램을 실행시키기 얼마나 쉬운지 보여주기 위함
#include <unistd.h>
#include <stdio.h>
int main(int argc, char* argv[]) // argc: 명령어로 전달되는 인자의 개수
// argv: main()에 실질적으로 전달되는 데이터,
// 문자열의 배열을 의미한다.
{
char arglist[3]; // 크기 3짜리 문자열 리스트, 이름은 arglist
arglist[0] = "ls"; // 첫번째 칸은 "ls" 실행할 프로그램의 경로를 나타냄
arglist[1] = "-l"; // 두번째 칸은 "-l" ls명령어에 전달할 옵션
arglist[2] = 0; // 세번째 칸은 "0" 배열의 끝 표시
printf("*** About to exec 'ls -l' \n"); // 실행할 명령어를 나타내는 메세지,
// 여기선 ls -l을 실행합니다~ 라고 표시
execvp("ls", arglist); // execvp함수를 호출하여 ls실행
// arglist에 포함된 인자들 전달
printf("*** ls is done. Bye\n"); // 프로그램종료, 안녕~!
}
결국 이 코드는 execvp함수를 사용하면, 프로그램을 프로세스에 할당하는게 얼마나 쉬운지 보여주기 위함이다
이제 무슨 일이 벌어지는지 살펴보자,
이 쯤에서 슬슬 머리가 어질어질하다.
원래 우리가 배우려 했던 학습목표가 뭐였는지 다시 알아보고 공부를 시작해보자