问题描述
我对Linux很陌生,所以请多多包涵。我正在尝试从终端执行命令行参数,每个参数都是可执行文件的完整路径。例如,这样的命令行:
./cmdarguments /Desktop/darren/lab01/c_ex1/a.out
表示cmdarguments
是我的父程序,下面的命令行是我希望执行的文件的路径,该文件只打印出hello world
。
到目前为止,这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char* argv[])
{
int counter;
for(counter = 0; counter < argc; counter++){
pid_t pid = fork();
if(pid < 0)
{
perror("Forking Failed\n");
exit(1);
}
else if(pid == 0)
{
char *args[] = {argv[counter],NULL};
execvp(args[0],args);
printf("Command completed.\n");
exit(0);
}
}
exit(0);
}
我了解我的代码中可能遗漏了很多东西,而从在线阅读的内容来看,我只会更加困惑自己。仅使用fork
和exec
意味着这是一个简单的任务。现在,我当前的输出仅为Command completed
,无论我用作第二个命令行参数的内容似乎没有变化,它始终为Command completed
。
解决方法
关于程序的一些注意事项:
-
exec*
函数家族在成功的情况下不会返回。这些函数将用参数指定的新函数替换整个过程。这些功能仅在发生故障的情况下返回,并且可以从errno
或通过perror
(显示errno
的描述)中读取错误。 the man pageman execvp
中定义了可能的错误。您应该在perror()
之后使用exec*()
,以打印出错误。您的输出始终为
Command completed
,因为您的execvp()
调用总是失败。 -
exec*
函数家族不需要不需要了解有关“父”进程的任何信息(父进程实际上没有任何意义,因为它们取代了当前进程而不管它是什么)父母或子女)。唯一的参数是(取决于您使用的变体)新的过程路径,其参数和环境。 -
传递给main的
argv
参数将始终包含位置0
的当前进程的名称,并且这些参数将紧随其后(直到argc - 1
)。 -
perror()
函数接收一个字符串,然后打印该字符串,后跟冒号,错误说明和换行符。您应该perror("x")
,而不是perror("x\n")
。 -
如果某件事失败并且您的程序无法继续,通常最好退出一个数字,使其与
0
不同,以向调用方(或您,如果您正在外壳中运行它。 -
在
exit()
中使用main()
是没有意义的,return
将具有相同的效果,因为它是主程序。如果要从与exit()
不同的函数中终止程序,则main()
函数很有用。 -
据我所知,
/Desktop/darren/lab01/c_ex1/a.out
在普通UNIX系统上通常不是有效路径。通常,您的主目录中有Desktop
。您可能要使用~/Desktop/...
或$HOME/Desktop/...
或/home/yourname/Desktop/...
甚至是诸如./a.out
之类的相对路径。
以上所述,您的代码的正确版本为:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char* argv[])
{
unsigned counter;
for(counter = 1; counter < argc; counter++) {
pid_t pid = fork();
if(pid < 0)
{
perror("fork failed");
return 1;
}
else if(pid == 0)
{
char *args[] = {argv[counter],NULL};
execvp(args[0],args);
// OR,equivalent to the above two lines:
// execlp(argv[counter],argv[counter],NULL);
fprintf(stderr,"%s: ",argv[counter]);
perror("execvp failed");
return 1;
}
}
return 0;
}
示例输出:
$ ./cmdarguments ls pwd
cmdarguments x.c
/home/marco/test
$ ./cmdarguments /bin/ls /bin/pwd
cmdarguments x.c
/home/marco/test
$ ./cmdarguments /does/not/exist
/does/not/exist: execvp failed: No such file or directory