我在同一目录中有两个文件。
directory/
| a.c
| b.c
a.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
pid_t pid;
int status;
int wret;
if ((pid = fork()) < 0)
printf("error");
else if(pid == 0)
{
printf("%s", argv[1]);
execv(argv[1], &argv[1]);
}
else
{
/* respawn */
if ((wret = wait(&status)) != -1)
execv(argv[1], &argv[1]);
}
return 0;
}
b.c只是一个打印“你好”的简单程序。
我想从命令行运行./a b
以使a
程序调用{{1}}执行exexXX
程序。
我不明白为什么如果我使用b
我只能在命令行中编写execv
,而是如果我使用./a b
我必须写execvp
。
./a ./b
页面不明确,因为它报告了
“这些函数的初始参数是文件的名称 将被执行。“
由于
答案 0 :(得分:3)
如果程序名称参数不包含斜杠,execvp()
函数将查找要在PATH环境变量中列出的目录中执行的程序。如果PATH上没有.
(当前目录)且您不在路径中列出的某个目录中,则不会执行b
这样的普通名称,即使b
位于当前目录中。如果名称包含斜杠,则它可以是相对的(./b
)或绝对的(/home/someone/src/programs/b
),它将被解释为要在不咨询PATH环境变量的情况下执行的文件名。
相比之下,execv()
将程序名参数中的普通b
视为./b
- 当前目录中文件的名称,如果存在则执行它,并失败如果它位于其他地方。
曾经有一条评论说:
您是说如果
.
中有可执行文件b并且您execv("b", b_args)
,它会被执行吗?
在正常的Unix机器上,是的。
代码b.c
:
#include <stdio.h>
int main(void)
{
puts("Hello");
return 0;
}
代码a.c
:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
char *argv[] = { "b", 0 };
execv(argv[0], argv);
fprintf(stderr, "failed to execute '%s'\n", argv[0]);
return 1;
}
运行这些:
$ (PATH=$(clnpath "$PATH" ".:$PWD"); echopath PATH; ./a)
/Users/jleffler/bin
/opt/informix/12.10.FC6/bin
/Users/jleffler/oss/bin
/Users/jleffler/oss/rcs/bin
/usr/local/mysql/bin
/opt/gcc/v7.3.0/bin
/Users/jleffler/perl/v5.24.0/bin
/usr/local/bin
/usr/bin
/bin
/opt/gnu/bin
/usr/sbin
/sbin
Hello
$
clnpath
脚本通过删除第二个路径类参数("$PATH"
)中列出的任何目录名称的出现来修改作为其第一个参数(".:$PWD"
)提供的字符串。 - 这是我在需要时动态编辑PATH的方式。 echopath
脚本回显PATH
上的目录(或任何其他类似路径的变量,或者它将处理扩展路径类变量的结果,例如"$PATH"
),每行一个 - 输出显示,.
和/Users/jleffler/soq
(我运行程序的位置)都不在子shell中的$PATH
上。 ./a
运行来自a.c
的代码(如果没有前面的./
则不会执行),而代码会运行来自b.c
的代码,该代码会生成Hello
1}}。 (如果有一些系统不起作用,请识别它。)
我还可以安排b.c
:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
puts("Hello");
const char *env = "PATH";
char *val = getenv(env);
if (val == 0)
val = "<nothing>";
printf("%s=%s\n", env, val);
return 0;
}
将直接从可执行文件中打印$PATH
的值(以验证是否列出了.
和当前工作目录的值。)