我应该编写一个更像是命令提示符的解释程序。这是一些背景信息:
General flow of basic interpreter
1. Prompt for user request.
2. Carry out the user request.
3. Unless user terminates the program, go to step 1.
Run a command. Format:
R command_path [arg1 to arg4]
//a single character ‘R’ which stands for 'Run', followed by the path of the command
//the user can supply up to 4 command line arguments
Behavior:
a. If command exist, run the command in a child process with the supplied
command line arguments
Wait until the child process is done
b. Else print error message “XXXX not found”, where XXXX is the user
entered command
E.g。
YWIMC > R /bin/ls
a.out ex2.c ...... //output from the “ls” command
YWIMC > R /bin/ls –l //same as executing “ls –l”
total 144
-rwx------ 1 sooyj compsc 8548 Aug 13 12:06 a.out
-rwx------ 1 sooyj compsc 6388 Aug 13 11:36 alarmClock
.................... //other files not shown
我到目前为止的想法是,在文件路径中读取,读入参数,使用execv(filePath,args)。但是,我无法获得循环和语法。
while(scanf("%s", args[i]) !=0) { //read in arguments
i++;
}
execv(filePath,args);
这读取了无数个参数。正如我所说,我无法正确使用语法。在C中处理字符串是一种痛苦:(
重新编辑。这是我目前的代码,相当不完整
#include <stdio.h>
#include <fcntl.h> //For stat()
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> //for fork(), wait()
int main()
{
char request, filePath[100];
int result, pathExist, childID, status;
struct stat buf;
//read user input
printf("YWIMC > ");
scanf("%c", &request);
while (request != 'Q'){ //if 'Q' then just exit program
// Handle 'R' request
scanf("%s", &filePath); //Read the filePath/program name
pathExist = stat(filePath, &buf);
if(pathExist < 0) {
printf("%s not found\n", filePath);
}
else {
result = fork();
if(result != 0) { //Parent Code
childID = wait(&status);
}
else { //Child Code
if(strcmp(filePath, "/bin/ls") == 0) {
execl("/bin/ls", "ls", NULL); //change to execv
} //with the use of a 2D
//string array
else { //same for this
execl(filePath, NULL);
}
return 256;
}
}
fflush(stdin); //remove all left over inputs
printf("YWIMC > ");
scanf("%c", &request);
}
printf("Goodbye!\n");
return 0;
}
答案 0 :(得分:4)
YWIMC
解释器环境,并能够使用传递给command not found
的命令处理执行中的execv
和错误,并在成功后返回YWIMC
命令,您必须fork
调用execv
到单独的进程,以防止execv
终止该程序。
基本上,您创建YWIMC
shell,其外部while
循环显示提示并在每次迭代时读取命令行(cmdline
)。在循环中,分隔命令行的最简单方法是使用下面使用的strtok
或strsep
(strtok
)。您可以通过在strtok
循环中调用for
来简化该过程:
for (p = strtok (line, " \n");
p && i < MAXA - 1;
p = strtok (NULL, " \n"))
cmdline[i++] = strdup (p);
注意: strtok
修改原始字符串,因此您必须复制字符串才能提供包含原始命令行的error
消息。< / p>
如果用户输入请求R
作为第一个令牌且至少有一个附加参数,则fork
进程。pid == 0
。在孩子(/path/to/command
)中,您将正确的execv
和参数传递给args
。传递正确命令和参数的最简单方法是创建指向cmdline
的第二个元素的指针R
(以便execv
从传递给{{的数组中被有效地丢弃1}})。在将错误命令传递给execv
的情况下,您还需要为子进程提供一种退出的方法(否则用户会想知道为什么他们必须输入q
两次才能在错误命令输出后退出通过。)
此时,执行命令最多为execv
,或者失败时提供错误。当用户输入q
时,shell将需要释放strdup
分配的所有内存,然后退出。
尝试以下操作,让我知道我是否终于理解了您的尝试。如果您有任何问题,请告诉我。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
/* MAXC - maximum characters that can be entered by user at prompt
MAXA - maximum arguments to read (R + path + 1 2 3 4 + NULL) */
#define MAXC 256
#define MAXA 7
void trimcrnl (char *s);
int main (void) {
char line[MAXC] = {0};
printf ("\n Entering 'YWIMC' environment\n"
" usage: R command_path [arg1 to arg4]\n"
" ('q' to quit).\n\n");
while (printf ("YWIMC > ") &&
fgets (line, MAXC, stdin))
{
if (*line == 'q') break;
if (*line != 'R') continue;
trimcrnl (line); /* strip newline from end of line */
char *p = line;
char *cmdline[MAXA] = {NULL};
char **args = &cmdline[1];
char *err = strdup (line);
int i = 0, nargs = 0, status = 0;
pid_t pid;
/* parse line into separate tokens (arguments) */
for (p = strtok (line, " \n");
p && i < MAXA - 1;
p = strtok (NULL, " \n"))
cmdline[i++] = strdup (p);
nargs = i; /* save the number of arguments found */
if (nargs < 2) continue;
#ifdef DEBUG
/* output command line & arguments read */
for (i = 0; i < nargs; i++)
printf (" cmdline[%d] = %s\n", i, cmdline[i]);
for (i = 0; i < nargs - 1; i++)
printf (" args[%d] = %s\n", i, args[i]);
#endif
if ((pid = fork ()) == -1) {
fprintf (stderr, "error: fork failed returning -1.\n");
exit (EXIT_FAILURE);
}
if (pid == 0) { /* child process */
/* call execv (NOTE: you must provide a full-path
to the program being executed, e.g. /usr/bin/ls)
*/
if (execv (args[0], args) == -1)
fprintf (stderr, "error: '%s' not found.\n", err);
_exit (EXIT_FAILURE);
}
waitpid (pid, &status, 0);
}
return 0;
}
/* strip newline or carriage return from string 's' */
void trimcrnl (char *s)
{
if (!s) return;
size_t len = strlen (s);
while (len > 0 && (s[len-1] == '\n' || s[len-1] == '\r'))
s[--len] = 0;
}
<强>编译强>
$ gcc -Wall -Wextra -o bin/execvargs execvargs.c
或在启用调试输出的情况下编译:
$ gcc -Wall -Wextra -o bin/execvargs execvargs.c -DDEBUG
使用/输出强>
$ ./bin/execvargsfile
Entering 'YWIMC' environment
usage: R command_path [arg1 to arg4]
('q' to quit).
YWIMC > anything not starting with 'R'
YWIMC > R badpath badcommand
error: 'R badpath badcommand' not found.
YWIMC > R /bin/ls /home/david/cnf/LVM
Lvm.pdf
YWIMC > R /bin/ls -al /home/david/cnf/LVM
total 380
drwxr-xr-x 2 david david 4096 May 21 22:22 .
drwxr-xr-x 41 david david 4096 Aug 27 17:58 ..
-rw-r--r-- 1 david david 380862 May 21 22:22 Lvm.pdf
YWIMC > q