先上代碼
shell.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAXLINE 4096 /* max line length */
int main(int argc, char *argv[])
{
char buf[MAXLINE];
pid_t pid;
int status;
printf("%% "); /* print prompt (printf requires %% to print %) */
while (fgets(buf, MAXLINE, stdin) != NULL) {
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0'; /* replace newline with NULL */
if ((pid = fork()) < 0) {
perror("fork error");
} else if (pid == 0) { /* child */
execlp(buf, buf, (char *)0); /* The exec() functions return only if an error has occurred. */
fprintf(stderr, "couldn't execute: %s: %s\n", buf, strerror(errno));
exit(127);
} else { /* parent */
if ((pid = waitpid(pid, &status, 0)) < 0)
perror("waitpid error");
printf("%% ");
}
}
exit(0);
}
編譯
$ gcc shell.c -o shell
運行
$ ./shell
% date
2021年 06月 06日 星期日 01:56:28 CST
% who
liyongjun :0 2021-05-23 09:43 (:0)
liyongjun tty3 2021-05-23 20:24
liyongjun tty4 2021-05-25 00:23
liyongjun pts/2 2021-05-25 00:50 (127.0.0.1)
% ls
shell shell.c
% ^D
$
再講程式
- 以上代碼便實作了一個簡單的 shell 程式,該程式從標準輸入讀取命令,然后執行這些命令,
- 該程式使用了一個不同的提示符(%),以區別與系統自帶的 shell 的提示符,
- 第 18 行用標準 I/O 函式 fgets 從標準輸入一次讀取一行,當鍵入檔案結束符(通常是 Ctrl + D)作為行的第一個字符時,fgets 回傳一個 NULL 指標,于是回圈停止,行程也就終止,
- 因為 fgets 回傳的每一行都以換行符終止,后隨一個 NULL 位元組,故用標準 C 函式 strlen 計算此字符的長度,然后用一個 NULL 位元組替換換行符,這樣做是因為 execlp 函式要求引數以 NULL 而不是以換行符結束,
- 呼叫 fork 創建一個新行程,新行程是呼叫行程的復制品,我們稱呼叫行程為父行程,新創建的行程為子行程,fork 向父行程回傳新子行程的行程 ID(大于 0),對子行程則回傳 0,因為 fork 創建一新行程,所以說它被呼叫一次(由父行程),但回傳兩次(分別在父行程及子行程中),
- 在子行程中,呼叫 execlp 以執行從標準輸入讀入的命令,這就用新的行程檔案替換了子行程原先執行的程式檔案,fork 和跟隨其后的 exec 兩者的組合就是某些作業系統所稱的產生(spawn)一個新行程,在 UNIX 系統中,這兩個部分相互分隔,構成兩個函式,
- 子行程呼叫 execlp 執行新程式檔案,而父行程希望等待子行程終止,這一要求由呼叫 waitpid 實作,其引數指定要等待的行程(在這里,pid 引數是子行程 ID),waitpid 函式回傳子行程的終止狀態(status 變數),在此簡單程式中,沒有使用該值,如果需要,可以用此值準確地判定子行程是因何終止的,
- 該程式的最主要缺陷是不能向所執行的命令傳遞引數,例如不能對 ls 指定目錄名,只能對作業目錄執行 ls 命令,為了傳遞引數,先要分析輸入行,然后用某種約定把引數分開(很可能使用空格或制表符),然后將分隔后的各個引數傳遞給 execlp 函式,后面有時間的話可以繼續完善,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/286515.html
標籤:其他
