使用 fork/execvp 在 C 中编写一个简单的 shell
Writing a simple shell in C using fork/execvp
我必须使用系统调用 fork()/execvp() 在 C 中开发一个简单的 shell。到目前为止,我的代码接受了一个命令,使用 strtok 将其拆分为一个数组 argv,然后我调用 fork 来创建一个子对象并执行该命令。我在 ubuntu 中处理此问题,其中大多数命令都在 /bin/ 目录中,因此我附加了程序名称(例如 /bin/ls)并将其用于 execvp 的第一个参数,然后我给它 argv 数组。如果我输入命令 "ls",我的程序就可以运行,但是在尝试其他命令甚至 "ls -l" 时,我得到一个 "ls: invalid option." 我不确定我在这里做错了什么。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_LEN 1024
int main(){
char line[BUFFER_LEN]; //get command line
char* argv[100]; //user command
char* path= "/bin/"; //set path at bin
char progpath[20]; //full file path
int argc; //arg count
while(1){
printf("My shell>> "); //print shell prompt
if(!fgets(line, BUFFER_LEN, stdin)){ //get command and put it in line
break; //if user hits CTRL+D break
}
if(strcmp(line, "exit\n")==0){ //check if command is exit
break;
}
char *token; //split command into separate strings
token = strtok(line," ");
int i=0;
while(token!=NULL){
argv[i]=token;
token = strtok(NULL," ");
i++;
}
argv[i]=NULL; //set last value to NULL for execvp
argc=i; //get arg count
for(i=0; i<argc; i++){
printf("%s\n", argv[i]); //print command/args
}
strcpy(progpath, path); //copy /bin/ to file path
strcat(progpath, argv[0]); //add program to path
for(i=0; i<strlen(progpath); i++){ //delete newline
if(progpath[i]=='\n'){
progpath[i]='[=12=]';
}
}
int pid= fork(); //fork child
if(pid==0){ //Child
execvp(progpath,argv);
fprintf(stderr, "Child process could not do execvp\n");
}else{ //Parent
wait(NULL);
printf("Child exited\n");
}
}
}
无效的选项是因为fgets()
在你回车的时候保留了'\n'
,试试这个
if(!fgets(line, BUFFER_LEN, stdin))
break;
size_t length = strlen(line);
if (line[length - 1] == '\n')
line[length - 1] = '[=10=]';
当您尝试调用 ls -l
时,您传递的是 "-l\n"
作为选项,因此是消息。
你将不得不改变
strcmp(line, "exit\n")
到
strcmp(line, "exit")
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#define BUFFER_LEN 1024
int main(){
char user_input[BUFFER_LEN]; //get command line
char* argv[120]; //user command
int argc ; //argument count
char* path= "/bin/"; //set path at bin
char file_path[50];//full file path
while(1){
printf("Simple Shell>> "); // Greeting shell during startup
if(!fgets(user_input,BUFFER_LEN, stdin)){
break; //break if the command length exceed the defined BUFFER_LEN
}
size_t length = strlen(user_input);
if(length == 0){
break;
}
if (user_input[length - 1] == '\n'){
user_input[length - 1] = '[=10=]'; // replace last char by '[=10=]' if it is new line char
}
//split command using spaces
char *token;
token = strtok(user_input," ");
int argc=0;
if(token == NULL){
continue;
}
while(token!=NULL){
argv[argc]=token;
token = strtok(NULL," ");
argc++;
}
argv[argc]=NULL;
strcpy(file_path, path); //Assign path to file_path
strcat(file_path, argv[0]); //conctanate command and file path
if (access(file_path,F_OK)==0){ //check the command is available in /bin
pid_t pid, wpid;
int status;
pid = fork();
if (pid == 0) { //child process
if (execvp(file_path,argv) == -1) {
perror("Child proccess end");
}
exit(EXIT_FAILURE);
}
else if (pid > 0) { // parent process
wpid = waitpid(pid, &status, WUNTRACED);
while (!WIFEXITED(status) && !WIFSIGNALED(status)){
wpid = waitpid(pid, &status, WUNTRACED);
}
}
else {
perror("Fork Failed"); //process id can not be null
}
}
else {
printf("Command is not available in the bin\n"); //Command is not available in the bin
}
}
}
我必须使用系统调用 fork()/execvp() 在 C 中开发一个简单的 shell。到目前为止,我的代码接受了一个命令,使用 strtok 将其拆分为一个数组 argv,然后我调用 fork 来创建一个子对象并执行该命令。我在 ubuntu 中处理此问题,其中大多数命令都在 /bin/ 目录中,因此我附加了程序名称(例如 /bin/ls)并将其用于 execvp 的第一个参数,然后我给它 argv 数组。如果我输入命令 "ls",我的程序就可以运行,但是在尝试其他命令甚至 "ls -l" 时,我得到一个 "ls: invalid option." 我不确定我在这里做错了什么。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_LEN 1024
int main(){
char line[BUFFER_LEN]; //get command line
char* argv[100]; //user command
char* path= "/bin/"; //set path at bin
char progpath[20]; //full file path
int argc; //arg count
while(1){
printf("My shell>> "); //print shell prompt
if(!fgets(line, BUFFER_LEN, stdin)){ //get command and put it in line
break; //if user hits CTRL+D break
}
if(strcmp(line, "exit\n")==0){ //check if command is exit
break;
}
char *token; //split command into separate strings
token = strtok(line," ");
int i=0;
while(token!=NULL){
argv[i]=token;
token = strtok(NULL," ");
i++;
}
argv[i]=NULL; //set last value to NULL for execvp
argc=i; //get arg count
for(i=0; i<argc; i++){
printf("%s\n", argv[i]); //print command/args
}
strcpy(progpath, path); //copy /bin/ to file path
strcat(progpath, argv[0]); //add program to path
for(i=0; i<strlen(progpath); i++){ //delete newline
if(progpath[i]=='\n'){
progpath[i]='[=12=]';
}
}
int pid= fork(); //fork child
if(pid==0){ //Child
execvp(progpath,argv);
fprintf(stderr, "Child process could not do execvp\n");
}else{ //Parent
wait(NULL);
printf("Child exited\n");
}
}
}
无效的选项是因为fgets()
在你回车的时候保留了'\n'
,试试这个
if(!fgets(line, BUFFER_LEN, stdin))
break;
size_t length = strlen(line);
if (line[length - 1] == '\n')
line[length - 1] = '[=10=]';
当您尝试调用 ls -l
时,您传递的是 "-l\n"
作为选项,因此是消息。
你将不得不改变
strcmp(line, "exit\n")
到
strcmp(line, "exit")
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#define BUFFER_LEN 1024
int main(){
char user_input[BUFFER_LEN]; //get command line
char* argv[120]; //user command
int argc ; //argument count
char* path= "/bin/"; //set path at bin
char file_path[50];//full file path
while(1){
printf("Simple Shell>> "); // Greeting shell during startup
if(!fgets(user_input,BUFFER_LEN, stdin)){
break; //break if the command length exceed the defined BUFFER_LEN
}
size_t length = strlen(user_input);
if(length == 0){
break;
}
if (user_input[length - 1] == '\n'){
user_input[length - 1] = '[=10=]'; // replace last char by '[=10=]' if it is new line char
}
//split command using spaces
char *token;
token = strtok(user_input," ");
int argc=0;
if(token == NULL){
continue;
}
while(token!=NULL){
argv[argc]=token;
token = strtok(NULL," ");
argc++;
}
argv[argc]=NULL;
strcpy(file_path, path); //Assign path to file_path
strcat(file_path, argv[0]); //conctanate command and file path
if (access(file_path,F_OK)==0){ //check the command is available in /bin
pid_t pid, wpid;
int status;
pid = fork();
if (pid == 0) { //child process
if (execvp(file_path,argv) == -1) {
perror("Child proccess end");
}
exit(EXIT_FAILURE);
}
else if (pid > 0) { // parent process
wpid = waitpid(pid, &status, WUNTRACED);
while (!WIFEXITED(status) && !WIFSIGNALED(status)){
wpid = waitpid(pid, &status, WUNTRACED);
}
}
else {
perror("Fork Failed"); //process id can not be null
}
}
else {
printf("Command is not available in the bin\n"); //Command is not available in the bin
}
}
}