我正在做一个使用Linux命令函数execvp()
练习C的模拟shell程序。我知道每当返回值小于0时,执行execvp
中传递的命令时出错。我对我的stringTok()
函数进程句子数组正确传入正确的自我打印他们是正面的长度和字符串值用于双重检查。对于句子的最后一个标记,基本上是将参数列表划分为单个标记,我将'\0'
字符分配给该标记的最后一个字符。
最终,每个单独的令牌被分配到char*cmdargv[MAX_LINE]
中的stringTok()
。 execvp(cmdargv[0], cmdargv)
是我传递命令参数的方式。例如," ls -al"是输入,fgets()
函数将该字符串读入args[MAX_LINE]
。子进程将运行execvp
,但返回负值并打印出错误字符串。当我尝试在代码中注释为cmd和argv手动分配值时,这甚至无法正常工作。我想我必须在execvp()
中传递错误的值或做错了什么
理想情况下,如果我键入" ls -al",它应该与在linux shell中完全相同,列出当前目录中的所有文件或目录(预期输出)。
输入:
osh> ls -al
的输出:
ARGS:
len 2
内容:ls
最后的元素115
len 3
内容:-al
最后的元素108
最后一名成员:( null)
osh>错误::坏地址
最后一名成员:( null)
职业安全与卫生>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#define MAX_LINE 80
int stringTok(char* sentence, char** tokens) {
const char* delim = " \r\n";
int count = 0;
// make copy of sentence for strtok
size_t len = strlen(sentence);
char *copy = malloc(len+1);
if(!copy) return 0; // if copy null, return 0
strncpy(copy, sentence, len);
copy[len] = '\0';
// Allocate and copy tokens
for(char* word = strtok(copy, delim);
word;
word = strtok(NULL, delim))
{
size_t len = strlen(word);
tokens[count] = malloc(len+1);
if(!tokens[count]) break;
strncpy(tokens[count], word, len);
tokens[count][len] = '\0';
count++;
}
size_t strlenth = strlen(tokens[count - 1]);
//if(count > 1) {
// tokens[count - 1][strlenth -1] = '\0';
//}
tokens[count] = NULL;
return count;
}
int main(void) {
char args[MAX_LINE]; // command to be executed
char *cmdargv[MAX_LINE]; // command tokens
int should_run = 1;
do {
printf("osh>");
fflush(stdout);
fgets(args, MAX_LINE, stdin);
//fflush(stdout);
printf("args:<%s>\n", args);
int count = stringTok(args, cmdargv);
for(int i = 0; i < count; i++) {
printf("len %ld\n", strlen(cmdargv[i]));
printf("content: %s\n", cmdargv[i]);
printf("last elememnt %d\n", cmdargv[i][strlen(cmdargv[i]) - 1]);
}
cmdargv[count] = NULL;
printf("last member:%s", cmdargv[count]);
//printf("cmdargv:%s\n", cmdargv[0]);
//printf("cmdargc:%d\n", cmdargv[0][strlen(cmdargv[0]) - 1]);
int pid = fork();
char *cmd = "ls";
char *argv[3];
argv[0] = "ls";
argv[1] = "-la";
if(pid == 0) {
execvp(cmd, argv);
if(execvp(cmd, argv) < 0) {
//printf("Error Executing Command\n");
perror("Error:");
}
} else if (pid > 0) {
// if '&' {
// wait(&pid)
//}
} else {
printf("Fork failed\n");
exit(1);
}
printf("\n");
} while(should_run);
return 0;
}
答案 0 :(得分:2)
终止
execv()
,execvp()
和execvpe()
函数提供了一个数组 指向以null结尾的字符串的指针,表示参数列表 可用于新计划。第一个论点,按照惯例, 应指向与正在执行的文件关联的文件名。 指针数组必须由空指针
由于数组只是作为C中的指针传递,并且调用函数没有隐藏的方法来知道数组的长度,因此必须明确给出它。在单独的参数中(例如,size
到fgets()
的参数),或者以已知值结尾的数组,如NULL
(与execv*
一样)。您的代码没有将最终参数设置为NULL
,这可能导致execlp
返回错误地址错误或类似错误,因为您设置的未初始化值将被视为指针并且很可能指向无效的内存地址。
修复该问题会使exec
在我这里工作。
此外,您应该使用perror()
之类的内容而不是常量错误消息来获取有关发生的错误的一些信息。如果exec
失败,子进程将继续运行,因此使用_exit()
终止它。
答案 1 :(得分:1)
以下是适用于我的代码版本。它在内存分配上有点清晰 - 你在父shell中疯狂泄漏(命令行的副本和每个参数的单独副本)。他们很容易清理。此代码正确处理EOF,而不是运行到无限循环。它会打印命令信息而不会崩溃。
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#define MAX_LINE 80
static int stringTok(char *sentence, char **tokens)
{
const char *delim = " ";
int count = 0;
size_t len = strlen(sentence);
char *copy = malloc(len + 1);
if (!copy)
return 0;
strncpy(copy, sentence, len);
copy[len] = '\0';
for (char *word = strtok(copy, delim);
word;
word = strtok(NULL, delim))
{
size_t len = strlen(word);
tokens[count] = malloc(len + 1);
if (!tokens[count])
break;
strncpy(tokens[count], word, len);
tokens[count][len] = '\0';
count++;
}
size_t length = strlen(tokens[count - 1]);
tokens[count - 1][length - 1] = '\0';
tokens[count] = 0;
free(copy);
return count;
}
int main(void)
{
char args[MAX_LINE]; // command to be executed
char *cmdargv[MAX_LINE]; // command tokens
int should_run = 1;
do
{
printf("osh>");
fflush(stdout);
if (fgets(args, MAX_LINE, stdin) == 0)
{
putchar('\n');
break;
}
printf("args:%s\n", args);
int count = stringTok(args, cmdargv);
for (int i = 0; i < count; i++)
{
printf("len %ld\n", strlen(cmdargv[i]));
printf("content: %s\n", cmdargv[i]);
printf("last character %d\n", cmdargv[i][strlen(cmdargv[i]) - 1]);
}
int pid = fork();
if (pid == 0)
{
for (int i = 0; cmdargv[i] != 0; i++)
fprintf(stderr, "%d: [%s]\n", i, cmdargv[i]);
execvp(cmdargv[0], cmdargv);
int errnum = errno;
fprintf(stderr, "Error executing command %s (%d: %s)\n",
cmdargv[0], errnum, strerror(errnum));
exit(1);
}
else if (pid < 0)
{
fprintf(stderr, "Fork failed\n");
exit(1);
}
else
{
for (int i = 0; cmdargv[i] != 0; i++)
free(cmdargv[i]);
int corpse;
int status;
while ((corpse = waitpid(0, &status, 0)) > 0)
fprintf(stderr, "PID %d exited with status 0x%.4X\n", corpse, status);
printf("\n");
}
} while (should_run);
return 0;
}
我的程序是可执行文件xv97
(来源xv97.c
):
$ make xv97
gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition xv97.c -o xv97
$ ./xv97
osh> extraordinary gallantry
args: extraordinary gallantry
len 13
content: extraordinary
last character 121
len 9
content: gallantry
last character 121
0: [extraordinary]
1: [gallantry]
Error executing command extraordinary (2: No such file or directory)
PID 17445 exited with status 0x0100
osh> ls -l .
args: ls -l .
len 2
content: ls
last character 115
len 2
content: -l
last character 108
len 1
content: .
last character 46
0: [ls]
1: [-l]
2: [.]
total 8488
-rw-r--r-- 1 jleffler staff 2223 Feb 14 13:40 README.md
drwxr-xr-x 19 jleffler staff 646 May 12 10:15 bin
-rwxr-xr-x 1 jleffler staff 8712 May 16 16:02 classifier
-rw-r--r-- 1 jleffler staff 637 May 8 08:21 classifier.c
drwxr-xr-x 3 jleffler staff 102 May 1 10:23 classifier.dSYM
drwxr-xr-x 10 jleffler staff 340 May 1 13:35 doc
drwxr-xr-x 7 jleffler staff 238 Feb 23 15:11 etc
drwxr-xr-x 18 jleffler staff 612 Apr 4 12:14 inc
-rwxr-xr-x 1 jleffler staff 8992 May 16 16:02 iq89
-rw-r--r-- 1 jleffler staff 2464 May 1 20:43 iq89.c
drwxr-xr-x 3 jleffler staff 102 Apr 20 11:56 iq89.dSYM
drwxr-xr-x 5 jleffler staff 170 Feb 14 13:40 lib
-rw-r--r-- 1 jleffler staff 390 May 1 13:35 makefile
drwxr-xr-x 168 jleffler staff 5712 May 12 11:56 src
-rwxr-xr-x 1 jleffler staff 9540 May 16 16:43 xv97
-rw-r--r-- 1 jleffler staff 2432 May 16 16:43 xv97.c
drwxr-xr-x 3 jleffler staff 102 May 16 15:55 xv97.dSYM
PID 17452 exited with status 0x0000
osh>^D
$
(我编辑了一些文件列表 - 这就是为什么尺寸与显示的文件大小相差无几的原因。)
我们可以讨论为什么最多一行每天只有80个字符。
我在运行macOS Sierra 10.12.5的Mac上进行测试,使用GCC 7.1.0作为编译器。