一個簡單的shell實現
什麼是內建命令
內建命令是由shell本身提供的命令,而不是透過外部程式(如位於/bin
、/usr/bin
等目錄下的可執行檔案)來執行的命令。這些命令在shell啟動的時候就載入到記憶體中,執行效率相對較高。
常見的內建命令有:cd
,pwd
,echo
。
什麼是當前路徑
本質就是程序的工作目錄,預設是程序在哪個目錄底下執行,它的工作目錄就是這個目錄。
那這個工作目錄可以更改嗎?答案是可以的,使用chdir()
函式就可以更改當前程序的工作目錄。
在我們自己實現一個簡單的shell,執行cd命令的時候,你會發現路徑沒有變化。那是因為在執行命令的時候,我們是使用fork()出來的子程序來執行的cd,子程序有自己的工作目錄(一般和父程序的工作目錄相同),當執行cd的時候,更改的是子程序的目錄,子程序執行完畢,什麼都沒了,繼續用的是父程序,即shell。
簡單的shell實現
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define NUM 1024
#define OP_NUM 64
char command[NUM];
char *myargv[OP_NUM];
int lastCode = 0;
int lastSig = 0;
int main()
{
while (1)
{
char *user = getenv("USER");
char *host = getenv("HOSTNAME");
printf("%s@%s 當前路徑#", user, host);
fflush(stdout);
char *s = fgets(command, sizeof(command) -1, stdin);//獲取命令列的輸入
assert(s != NULL);
(void)s;
//清除使用者按下的回車
command[strlen(command) - 1] = 0;
//字串切割
myargv[0] = strtok(command, " ");
int i = 1;
//顯示顏色
if (myargv[0] != NULL && strcmp(myargv[0], "ls") == 0)
{
myargv[i++] = (char*)"--color=auto";
}
//myargv[] 必須以NULL結尾,而strtok函式結束的時候返回NULL
//strtok()中的NULL表示從上次結束的位置繼續查詢下一個子串
while (myargv[i++] = strtok(NULL, " ")) {}
//不需要建立子程序,讓shell自己執行對應的命令
if (myargv[0] != NULL && strcmp(myargv[0], "cd") == 0)
{
if (myargv[1] != NULL) chdir(myargv[1]);
continue;
}
if (myargv[0] != NULL && myargv[1] != NULL && strcmp(myargv[0], "echo") == 0)
{
if (strcmp(myargv[1], "$?") == 0) printf("%d, %d\n", lastCode, lastSig);
else printf("%s\n", myargv[1]);
continue;
}
//建立子程序
pid_t id = fork();
assert(id != -1);
if (id == 0)
{
//程式替換
execvp(myargv[0], myargv);
exit(1);
}
int status = 0;
pid_t ret = waitpid(id, &status, 0);
assert(ret > 0);
(void)ret;
lastCode = WEXITSTATUS(status);
lastSig = WIFEXITED(status);
}
}