【问题标题】:execvp() return value if path is wrong如果路径错误,execvp() 返回值
【发布时间】:2019-07-06 06:48:12
【问题描述】:

我目前正在用 C 编写一个自定义 shell 脚本。为了执行命令,我使用了 execvp() 函数。例如:

if((execvp(args[0], args)) == -1) //args is a char **array containing the commands arguments
{
    printf("ERROR: Wrong command\n");
    exit(EXIT_FAILURE);
}

问题是,当两个命令用“&&”分隔时,如果第一个没有执行(因此,execvp 将返回-1),整个过程必须中断,然后才能进入下一个。它工作得很好,例如我写“一些随机错误的命令> && ls”。

虽然,如果我写类似“ ls 一些随机的错误路径> && ls ”,execvp() 将正常执行,并打印消息:

ls: cannot access '...': 没有这样的文件或目录

然后它会转到下一个命令。显然,在这种情况下 execvp() 不会返回 -1。

在这种情况下 execvp() 是否返回任何其他值?如果不存在,如何在执行命令前检查路径是否存在?

编辑 我只是检查状态的值(在父母等待孩子终止时由 wait(&status) 生成)。如果不为零,则表示该命令未执行。

【问题讨论】:

  • args 数组失败时到底有什么? args[0] 后跟NULL 中的shell 脚本名称?类似{ "sh", "-c", "your shell commands", NULL }?
  • 注意execvp(如果返回)的返回值是-1,而不是EXIT_FAILURE。如果返回,您可以查看errno
  • 对于foo && bar这样的命令,需要在子进程中fork并执行foo,然后等待其退出状态再决定是否需要fork-and-execbar .
  • 如果这是一个自定义的shell程序,大概你是从子进程调用execvp,而不是从主shell进程调用?您可以在主 shell 进程中添加代码以等待子进程退出,然后检查子进程的退出状态以决定如何继续。如果execvp函数在子进程中失败,那么子进程应该退出并报错,以便主shell进程可以检测到失败。
  • 如果ls报错你的execvp已经成功地用ls程序替换了你当前进程中的程序,所以execvp不会返回。您的进程将以退出代码ls 终止。可以在父进程调用waitpid查看退出码。

标签: c shell execvp


【解决方案1】:

在这种情况下 execvp() 是否返回任何其他值?

execvp 在这种情况下不会返回 any 值,因为它成功地运行了您要求它执行的命令。除非ls 已成功执行,否则您无法从ls 收到错误。您可能意味着您的 && 不仅在 exec 失败时短路,而且在 exec 进程返回非零状态代码的成功 exec 时短路(如 wait / waitpid 所示)。

如果不存在,如何在执行命令前检查路径是否存在?

一般来说,这没有任何意义。 shell 假设它正在运行的命令将如何解释它们的参数是不正常的,例如其中之一应该是现有文件的名称。即使您确实遇到过这种特殊情况,它也会受到竞争条件的影响(当 shell 检查时文件存在,但ls 运行时不存在,反之亦然)。

【讨论】:

  • 直到现在,我在父进程中有一个等待(&status)(execvp()在子进程中),然后我还检查了“if(WIFEXITED(status)&& WEXITSTATUS(status)= = EXIT_FAILURE)" 以便它返回 EXIT_FAILURE。还有什么我应该做的吗?
  • @ThanosManolis 不检查 == EXIT_FAILURE,检查 any 非零值(在 ls 的情况下,当文件列出时,它会以 2 退出命令行上不存在。很多程序针对不同的失败情况返回不同的值。只有0代表成功。)
  • 非常感谢!它只是检查状态是否非零。
【解决方案2】:

虽然,如果我写类似 " ls && ls ", execvp() 会正常执行,并打印信息:

ls: cannot access '...': 没有这样的文件或目录

然后它会转到下一个命令。显然,在这种情况下 execvp() 不返回 -1。

execvp() 的返回值报告是否成功执行了替换进程映像。它与任何替换的退出状态无关。当然,它只会在无法用新的过程映像替换当前过程映像时才返回。这是它可以工作的唯一方式,因为替换图像必须成功加载并启动,然后才能确定其退出状态,并且此时之前的图像不再可用于返回

在这种情况下 execvp() 是否返回任何其他值?

没有。

如果没有, 如何在执行命令前检查路径是否存在?

这是错误的策略。您的 shell 需要知道如何验证它可以执行的每个命令的所有操作数,以便在一般情况下使其工作。这对于允许执行任意程序的 shell 来说是根本不可能的。

您需要做的是通过waitwaitpid 获取第一个进程的退出状态。如果您甚至远程正确地执行此操作,那么您已经在使用其中一个来等待第一个进程的终止,然后再启动第二个进程,并且自然地,在进程实际终止之前您无法确定退出状态。 wait()waitpid() 函数都可以提供一个int“状态”代码,您可以从中提取有关已终止进程的各种信息,包括在正常终止的情况下的退出状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    相关资源
    最近更新 更多