构建简单的 unix shell 问题
Building simple unix shell problems
我是 unix 的新手,我在大学里有一个任务要用 c 语言构建一个简单的 shell,内置 cd 和 kill 命令。
这是我的代码,它不起作用..tbh 我不太了解它所以我并不惊讶它不起作用..你能帮我吗?也不知道我将如何执行 kill 命令。谢谢!
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 1024
const int ARGSIZE = 20;
void execute(char*args[])
{
int pid, status;
pid = fork();
if(pid<0)
{
perror("Error forking!");
}
else if(pid > 0)
{
while(wait(&status) != pid)
continue;
}
else if(pid == 0)
{
if (execvp(args[0], args) == -1)
{
perror("Error");
}
}
}
void cd(char*directory)
{
int ret = 0;
if(directory == '[=11=]')
directory = getenv("HOME");
ret = chdir(directory);
if(ret != 0)
fprintf(stderr,"Failed to enter directory: %s\n",directory);
else
printf("%s\n",directory);
}
int main()
{
char line[BUF_SIZE];
char *args[ARGSIZE];
int argIndex = 0;
while(1){
printf("> ");
fgets(line, BUF_SIZE, stdin);
char *token;
token = strtok(line," ");
while(token!=NULL)
{
args[argIndex]=token;
token = strtok(NULL," ");
argIndex++;
}
args[argIndex]=NULL;
if(strcmp(args[0], "quit") == 0 || strcmp(args[0], "exit") == 0)
break;
if(line== "\n")
printf("> ");
else if ((strcmp(args[0], "cd") == 0))
cd(args[1]);
else
execute(args);
}
return 0;
}
你走在正确的轨道上。有一些微妙的问题,您没有考虑将保留在 line
中的尾随 '\n'
作为提示符下输入的最后一个字符。在用于用 strtok
标记输入的定界符中包含 " \n"
将删除它,允许与最终标记进行有效的 strcmp
比较(例如,这就是为什么 quit
和 exit
不会退出应用程序)。
除此之外,您还可以做一些额外的事情 different/better,您可以处理输入的目录,例如'~/somedir'
,以及可以使用的类似附加检查。我在下面标注了大部分代码注释。
查看下面的更改,如果您有任何问题,请告诉我。总是可以添加额外的检查等等,但总的来说,你解决问题的方法非常好。 (注意:所做的一些更改是 non-substantive,例如 "shell> "
作为提示,而不是 "> "
。只需按照您的意愿处理其中的任何一个即可。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
enum {ARGSIZE = 20, BUF_SIZE = 1024};
void execute (char **args);
void cd (char *directory);
int killpid (char *pitstr, int sig);
int main (void)
{
char line[BUF_SIZE] = {0};
char *args[ARGSIZE] = {NULL};
char *token;
int i, argIndex = 0;
while (1) {
argIndex = 0; /* reinitialize variables */
for (i = 0; i < ARGSIZE; i++)
args[i] = NULL;
printf ("shell> "); /* prompt */
if (fgets (line, BUF_SIZE, stdin) == NULL) {
printf ("EOF received\n");
return 0;
}
if (*line == '\n') /* Enter alone */
continue;
token = strtok (line, " \n"); /* add \n to delimiters */
while (token != NULL) {
args[argIndex] = token;
token = strtok (NULL, " \n");
argIndex++;
}
if (!argIndex) continue; /* validate at least 1 arg */
if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
break;
/* handle 'cd' or 'kill' separately */
if ((strcmp (args[0], "cd") == 0))
cd (args[1]);
else if ((strcmp (args[0], "kill") == 0)) {
if (args[1]) killpid (args[1], SIGTERM);
}
else
execute (args);
}
return 0;
}
void execute (char **args)
{
int pid, status;
pid = fork ();
if (pid < 0) {
perror ("Error forking!");
return;
}
else if (pid > 0) {
while (wait (&status) != pid)
continue;
}
else if (pid == 0) {
if (execvp (args[0], args) == -1) {
perror ("Error");
}
_exit (EXIT_FAILURE);
}
}
void cd (char *directory)
{
char dir[BUF_SIZE] = {0};
if (!directory) { /* handle 'cd' */
directory = getenv ("HOME");
if (chdir (directory))
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
return;
}
if (*directory == '~') { /* handle cd ~/stuff */
strcpy (dir, getenv ("HOME"));
strcat (dir, "/");
strcat (dir, directory + 2);
if (chdir (dir))
fprintf (stderr, "Failed to enter directory: %s\n", dir);
else
printf ("%s\n", dir);
return;
}
if (chdir (directory)) /* handle given directory */
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
}
int killpid (char *pidstr, int sig)
{
pid_t pid = (pid_t)atoi (pidstr);
if (pid < 1) {
fprintf (stderr, "warning: requested pid < 1, ignoring\n");
return (int)pid;
}
printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
// return kill (pid, sig);
return 0;
}
样本Usage/Output
$ ./bin/ushell
shell> cd
/home/david
shell> cd ~/tmp
/home/david/tmp
shell> kill 18004
killing pid '18004' with signal '15'
shell>
shell> quit
我是 unix 的新手,我在大学里有一个任务要用 c 语言构建一个简单的 shell,内置 cd 和 kill 命令。 这是我的代码,它不起作用..tbh 我不太了解它所以我并不惊讶它不起作用..你能帮我吗?也不知道我将如何执行 kill 命令。谢谢!
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 1024
const int ARGSIZE = 20;
void execute(char*args[])
{
int pid, status;
pid = fork();
if(pid<0)
{
perror("Error forking!");
}
else if(pid > 0)
{
while(wait(&status) != pid)
continue;
}
else if(pid == 0)
{
if (execvp(args[0], args) == -1)
{
perror("Error");
}
}
}
void cd(char*directory)
{
int ret = 0;
if(directory == '[=11=]')
directory = getenv("HOME");
ret = chdir(directory);
if(ret != 0)
fprintf(stderr,"Failed to enter directory: %s\n",directory);
else
printf("%s\n",directory);
}
int main()
{
char line[BUF_SIZE];
char *args[ARGSIZE];
int argIndex = 0;
while(1){
printf("> ");
fgets(line, BUF_SIZE, stdin);
char *token;
token = strtok(line," ");
while(token!=NULL)
{
args[argIndex]=token;
token = strtok(NULL," ");
argIndex++;
}
args[argIndex]=NULL;
if(strcmp(args[0], "quit") == 0 || strcmp(args[0], "exit") == 0)
break;
if(line== "\n")
printf("> ");
else if ((strcmp(args[0], "cd") == 0))
cd(args[1]);
else
execute(args);
}
return 0;
}
你走在正确的轨道上。有一些微妙的问题,您没有考虑将保留在 line
中的尾随 '\n'
作为提示符下输入的最后一个字符。在用于用 strtok
标记输入的定界符中包含 " \n"
将删除它,允许与最终标记进行有效的 strcmp
比较(例如,这就是为什么 quit
和 exit
不会退出应用程序)。
除此之外,您还可以做一些额外的事情 different/better,您可以处理输入的目录,例如'~/somedir'
,以及可以使用的类似附加检查。我在下面标注了大部分代码注释。
查看下面的更改,如果您有任何问题,请告诉我。总是可以添加额外的检查等等,但总的来说,你解决问题的方法非常好。 (注意:所做的一些更改是 non-substantive,例如 "shell> "
作为提示,而不是 "> "
。只需按照您的意愿处理其中的任何一个即可。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
enum {ARGSIZE = 20, BUF_SIZE = 1024};
void execute (char **args);
void cd (char *directory);
int killpid (char *pitstr, int sig);
int main (void)
{
char line[BUF_SIZE] = {0};
char *args[ARGSIZE] = {NULL};
char *token;
int i, argIndex = 0;
while (1) {
argIndex = 0; /* reinitialize variables */
for (i = 0; i < ARGSIZE; i++)
args[i] = NULL;
printf ("shell> "); /* prompt */
if (fgets (line, BUF_SIZE, stdin) == NULL) {
printf ("EOF received\n");
return 0;
}
if (*line == '\n') /* Enter alone */
continue;
token = strtok (line, " \n"); /* add \n to delimiters */
while (token != NULL) {
args[argIndex] = token;
token = strtok (NULL, " \n");
argIndex++;
}
if (!argIndex) continue; /* validate at least 1 arg */
if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
break;
/* handle 'cd' or 'kill' separately */
if ((strcmp (args[0], "cd") == 0))
cd (args[1]);
else if ((strcmp (args[0], "kill") == 0)) {
if (args[1]) killpid (args[1], SIGTERM);
}
else
execute (args);
}
return 0;
}
void execute (char **args)
{
int pid, status;
pid = fork ();
if (pid < 0) {
perror ("Error forking!");
return;
}
else if (pid > 0) {
while (wait (&status) != pid)
continue;
}
else if (pid == 0) {
if (execvp (args[0], args) == -1) {
perror ("Error");
}
_exit (EXIT_FAILURE);
}
}
void cd (char *directory)
{
char dir[BUF_SIZE] = {0};
if (!directory) { /* handle 'cd' */
directory = getenv ("HOME");
if (chdir (directory))
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
return;
}
if (*directory == '~') { /* handle cd ~/stuff */
strcpy (dir, getenv ("HOME"));
strcat (dir, "/");
strcat (dir, directory + 2);
if (chdir (dir))
fprintf (stderr, "Failed to enter directory: %s\n", dir);
else
printf ("%s\n", dir);
return;
}
if (chdir (directory)) /* handle given directory */
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
}
int killpid (char *pidstr, int sig)
{
pid_t pid = (pid_t)atoi (pidstr);
if (pid < 1) {
fprintf (stderr, "warning: requested pid < 1, ignoring\n");
return (int)pid;
}
printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
// return kill (pid, sig);
return 0;
}
样本Usage/Output
$ ./bin/ushell
shell> cd
/home/david
shell> cd ~/tmp
/home/david/tmp
shell> kill 18004
killing pid '18004' with signal '15'
shell>
shell> quit