[英]Shell seems to recognize commands but doesn't execute them
我正在嘗試在類似unix的xv6 OS的Shell程序中實現基本命令執行。 我正在編輯的Shell代碼的一部分是runcmd函數,在這里我使用execvp命令執行終端中使用的命令。 當我編譯程序時,該程序編譯沒有錯誤,但是當我嘗試在命令行上鍵入命令時,沒有任何反應。 我已經閱讀了exec命令的手冊頁 ,但是我仍然不太了解需要在exec()命令中傳遞這些參數的正確方式,或者我什么時候需要使用哪個版本的exec()。對於OS編程來說還是很新的。
為了執行命令,我這里還沒有實現哪些功能? 我有以下runcmd函數的代碼:
我只是為每個命令添加了更多的exec語句和二進制文件的路徑。 但是,只有第一個exec命令有效(本例中為cd)。 當我使用任何其他命令時,命令行會像執行CD一樣執行它。 如何使它適用於多個命令?
struct cmd {
int type; // ' ' (exec), | (pipe), '<' or '>' for redirection
};
struct
execcmd {
int type; // ' '
char *argv[MAXARGS]; // arguments to the command to be exec-ed
};
// Execute cmd. Never returns.
void
runcmd(struct cmd *cmd)
{
int p[2], r;
struct execcmd *ecmd;
struct pipecmd *pcmd;
struct redircmd *rcmd;
if(cmd == 0)
exit(0);
switch(cmd->type){
default:
fprintf(stderr, "unknown runcmd\n");
exit(-1);
case ' ':
ecmd = (struct execcmd*)cmd;
if(ecmd->argv[0] == 0)
exit(0);
//fprintf(stderr, "exec not implemented\n");
execvp("/bin/cd" , ecmd->argv );
execvp("/bin/grep" , ecmd->argv );
execvp("/bin/echo" , ecmd->argv );
execvp("/bin/cat" , ecmd->argv );
execvp("/bin/ls" , ecmd->argv );
break;
case '>':
case '<':
rcmd = (struct redircmd*)cmd;
//fprintf(stderr, "redir not implemented\n");
execvp("/bin" , ecmd->argv );
runcmd(rcmd->cmd);
break;
case '|':
pcmd = (struct pipecmd*)cmd;
fprintf(stderr, "pipe not implemented\n");
int execl(const char *path, const char *arg, ...);
break;
}
exit(0);
}
您似乎正在嘗試執行“ / bin”目錄。
您應該使exec調用的第一個參數為用戶要運行的二進制文件。
當命令失敗時,使用perror函數還將為您提供有用的輸出。
我認為這是您真正需要的:
case ' ':
ecmd = (struct execcmd*)cmd;
if (ecmd->argv[0] == 0)
_exit(0);
execvp(ecmd->argv[0], ecmd->argv);
/* if control reaches this point, execvp failed */
perror(ecmd->argv[0]);
_exit(127);
您可能想知道為什么execvp
將argv[0]
交給它時,為什么execvp
將可執行文件作為與參數向量分開的單獨參數加載。 這是舊版功能; 如果我今天從頭開始設計此API,我認為我不會包含它。 但是,想法是程序可能會根據其argv[0]
不同而有所不同。 例如, ex
一天, ex
和vi
是相同的可執行文件 (到同一個inode的兩個硬鏈接-symlinks尚未發明),它基於argv[0]
決定以哪種模式啟動。 而且,自Unix誕生以來, login(1)
調用了將argv[0]
的第一個字符設置為'-'
的argv[0]
; 沒有/bin/-sh
,因此它實際上需要與參數向量分開指定要調用的程序的能力。
我目前無法想到shell會使用argv[0]
以外的任何東西作為execvp
的第一個參數的情況。
有關代碼其他更改的注釋:
_exit
上調用fork
的子級上的exit
。 strerror(errno)
都打印到stderr
而不是 stdout
。 perror
是此操作的方便快捷方式。 perror
調用安全,必須在fork
之前緊接在父級中調用fflush(0)
,並且您的C庫必須正確地實現stderr的行緩沖。 我之所以這樣說是因為XV6似乎是一個教學操作系統,您必須自己實現它的一部分,而且我不知道stdio是否是您的責任。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.