我正在用C创建自己的shell
fork
和
execvp
。我正在使用解析cmd及其参数
strtok
。打印解析后的标记向我证实,我确实收到了所有参数,而且shell通常都能工作,尽管它是非常基本的,因为我是一个十足的noob。然而,当我运行shell时,有两个典型的场景让我感到困惑,请注意
ls
和
pwd
命令第一次工作,但随后开始从某处获取这些额外的操作数:
â a2 ./shell
(user)># pwd
/home/user/ClionProjects/unix_programming/a2
(user)># ls -la
total 32
drwxrwxr-x 2 user user 4096 Mar 9 13:18 .
drwxrwxr-x 9 user user 4096 Mar 6 14:18 ..
-rwxrwxr-x 1 user user 13616 Mar 9 13:18 shell
-rw-rw-r-- 1 user user 3809 Mar 9 13:17 shell.c
-rw-rw-r-- 1 user user 545 Mar 9 12:58 shell.h
(user)># pwd
pwd: ignoring non-option arguments
/home/user/ClionProjects/unix_programming/a2
(user)>#
以及
a2/壳
(用户)>#pwd公司
/主页/用户/客户端项目/unix\u编程/a2
(用户)>#ls-la
总计32
drwxrwxr-x 2用户用户4096 3月9日13:18。
drwxrwxr-x 9用户用户4096 3月6日14:18。。
-RWXR-x 1用户用户13616 Mar 9 13:18 shell
-rw-rw-r—1用户用户3809 Mar 9 13:17 shell。c
-rw-rw-r--1个用户用户545 Mar 9 12:58 shell。h类
(用户)>#pwd公司
pwd:忽略非选项参数
/主页/用户/客户端项目/unix\u编程/a2
(用户)>#
在下面的代码中,您可以看到我将参数存储在
tokens
。第一个标记是cmd文件名本身。
我试过了
memset
ting公司
代币
全部为零,
free
ing it和re-
malloc
在while循环的每次迭代开始时对其进行初始化。我一直在尝试调整大小
代币
到其中当前的参数数。我做这些事是因为我相信,
代币
正在保留以前命令中由于某种原因被以后的命令读取的内容。然而,re-
马洛克
ing和
realloc
ing公司
代币
没有触及这个问题,所以我现在不知所措。任何朝着正确方向提出的建议或建议都将不胜感激。
壳h类
#ifndef UNIX_PROGRAMMING_SHELL_H
#define UNIX_PROGRAMMING_SHELL_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
int sig_int = 0;
void signal_handler(int sig_num);
void start_shell();
void prompt();
void change_dir(char *path, pid_t *pid, int *status);
void execute_cmd(const char *file_name, char *const *args);
void parse_cmd(char *cmd, char **tokens, size_t *index);
#endif //UNIX_PROGRAMMING_SHELL_H
壳c
#include "shell.h"
void signal_handler(int sig_num) {
printf("\n"); // Do nothing when Ctrl-C is pressed
}
void prompt() {
/* Get current users username and display prompt */
char *user = getlogin();
printf("(%s)># ", (user==NULL)? "": user);
}
void change_dir(char *path, pid_t *pid, int *status) {
*pid = fork();
if (*pid == -1) {
printf("Error changing directory..\n");
} else if (*pid == 0) {
chdir(path);
} else {
*pid = wait(status);
if (*pid == -1) {
printf("%s\n", strerror(errno));
return;
}
}
}
void execute_cmd(const char *file_name, char *const *args) {
execvp(file_name, args);
}
/** parse commands into tokens... **/
void parse_cmd(char *cmd, char **tokens, size_t *index) {
char *tok;
const char *delim = " ";
*index = 0;
// TODO: realloc tokens, so it can start from 2 and build up as needed
tok = strtok(cmd, delim);
if (tok != NULL) {
tokens[*index] = tok;
(*index)++;
} else {
tokens[*index] = "\0";
return;
}
while ((tok = strtok(NULL, delim)) != NULL) {
tokens[*index] = tok;
(*index)++;
}
// for (size_t i = 0; i < *index; i++) {
// printf("arg[%zu]: %s\n", i, tokens[i]);
// }
printf("\n");
}
void start_shell() {
ssize_t c;
size_t cmd_size = 20;
size_t num_args = 5;
int *status = NULL;
pid_t pid;
char *cmd = (char *) malloc(sizeof(char)); /* command line input */
char **tokens = (char **) malloc(sizeof(char *) * num_args); /* command line input parsed into tokens */
size_t *index = (size_t *) malloc(sizeof(size_t)); /* number of tokens parsed */
if (tokens == NULL) {
printf("Error: Out of memory..");
exit(EXIT_FAILURE);
}
prompt();
/* main loop - get input, parse, process - until termination */
while ( (c = getline(&cmd, &cmd_size, stdin)) != EOF ) {
cmd[strcspn(cmd, "\n")] = '\0'; /* trim newline */
parse_cmd(cmd, tokens, index);
/* resize tokens to fit only it's current contents */
// if (*index < num_args && *index != 0 && *index != 1) {
tokens = realloc(tokens, *index);
// }
const char *file_name = tokens[0];
char *const *args = tokens;
/* If command is blank */
if ( (c = strcspn(file_name, "\n\r\0") == 0) ) {
tokens[0] = "\0";
prompt();
continue;
} else if ( (c = strcmp(file_name, "exit")) == 0 ) {
break;
} else if ( (c = strcmp(file_name, "cd")) == 0 ) {
if (*index == 1) { /* no path provided */
chdir(getenv("HOME"));
} else {
char *path = realpath(args[1], NULL);
if (path == NULL) {
printf("%s\n", strerror(errno));
break;
} else {
change_dir(path, &pid, status);
}
}
}
// fork here ... success: parent < pid .. child << 0 -- failure: parent << -1
pid = fork();
if (pid == -1) {
printf("Error executing command\n");
continue;
} else if (pid == 0) {
execute_cmd(file_name, args);
} else {
pid = wait(status);
if (pid == -1) {
printf("%s\n", strerror(errno));
exit(EXIT_FAILURE);
}
}
tokens[0] = "\0";
prompt();
}
free(cmd);
free(tokens);
free(index);
printf("\n"); /* avoids unwanted terminal output for ctrl-D */
}
int main(void) {
signal(SIGINT, signal_handler);
start_shell();
return 0;
}