【问题标题】:Changing from system() to execvp() in C shell program在 C shell 程序中从 system() 更改为 execvp()
【发布时间】:2012-07-16 17:44:57
【问题描述】:

我正在用 C 编写一个简单的 shell。用户输入命令并将它们存储在一个二维数组中,例如:

SHELL$ ls ; date ; ls
// This is parsed into the following
char* commands[1000] = {"ls", "date", "ls"};

如果在整个程序中我没有该输入的特定角色,我有一个 for 循环将数组的每个元素传递给系统 - 我没有 ls 和日期的特定角色:

if (did_not_process == 0)
    system(commands[i]);

现在我想将 system() 转换为 execvp() 并拥有完全相同的功能。这是我的方法无法正常运行:

if (did_not_process == 0) {        
    command[0] = commands[i];
    command[1] = NULL;

    if (fork() == 0) {
        execvp(command[0], command);
    } else {
        wait(NULL); //wait for child to complete?
    }
}

唯一的问题是,当我通过 shell 的进一步迭代(一个简单的 while 循环)时,它会偶尔且无法控制地打印执行。问题出在我展示的代码中,但我不知道在哪里。

这是示例输出:

SHELL$ ls;date;ls
file
Mon Jul 16 13:42:13 EDT 2012
file
SHELL$ ls
SHELL$ file

第一次工作,然后在 shell 输入的同一行打印文件。

【问题讨论】:

  • 有什么理由不等待孩子本身
  • system() 通过 shell 运行任务,因此实际上执行的是 shell。您仍然可能会发现查看一个简单的工作实现很有用,例如 android.googlesource.com/platform/bionic/+/master/libc/unistd/…
  • 我相信 wait(NULL) 等着孩子。我弄错了吗?
  • 是的。它等待一个孩子,不一定是你刚刚产生的孩子。

标签: c linux shell


【解决方案1】:

根据一般原则,您应该检查系统调用的返回值是否有错误:

int cpid = fork()
if (cpid == -1) {
    perror("fork");
} else if (cpid == 0) {
    execvp(command[0], command);
    perror("execvp");
    _exit(1);
} else {
    if (waitpid(cpid, 0, 0) < 0)
        perror("waitpid");
}

【讨论】:

  • system(3) 不仅如此:它阻塞 SIGCHLD 并在调用进程中禁用 SIGINT 和 SIGQUIT。顺便说一句,这实际上是不使用它的原因之一(system(3)):想象一下当生成的进程也这样做并挂起时会发生什么。或者只是在一个紧密的循环中启动流程。因此,在某些情况下,您的代码可以被认为比 system(3) 更好:-)
猜你喜欢
  • 2011-10-30
  • 1970-01-01
  • 2011-10-18
  • 1970-01-01
  • 2014-03-02
  • 1970-01-01
  • 2021-05-03
  • 1970-01-01
  • 2016-08-17
相关资源
最近更新 更多