c++ - 如何停止执行第一个子进程?

标签 c++ fork

目标:设计一个 linux shell,它会提示用户输入,创建一个新进程来执行该命令,然后终止/退出该进程。这是我的代码

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

using namespace std;

string cmd; //global string so cmd copied to child to execute    

void HandleAsParent(){
    cout<<"Linux Shell 1.0\n";
    string s;
    while (!exitflag) {
        cout<<"myShell>";
        getline(cin,cmd); //Take user input
        fork();
        wait(NULL);
    }
}

void HandleAsChild(){
    cout<<"Executing";
    system(cmd.c_str());
}

int main() {
    pid_t p = fork();
    if(p != 0){
        HandleAsParent(); //This is parent process
    }
    else {
        HandleAsChild(); //This is child process
    }
}

问题是,由于主程序中的第一个 fork() 调用,

myShell>Executing

在程序运行时显示在第一行而不仅仅是

myShell>

. 我能够理解为什么会发生这种情况,但无法弄清楚如何阻止执行第一个子进程。 请为我的问题建议解决方法/解决方案。

Edit 1: This is one of my Assignment(for learning UNIX Processes) questions, and It is clearly stated that the program " prompts the user for a command, parses the command, and then executes it with a child process "

最佳答案

正如我已经猜到的,system() 可能使用了 fork()exec()wait( )。出于好奇,我在 woboq.org 上搜索了源代码并找到了一个:glibc/sysdeps/posix/system.c .

记住这一点,使用 system(),所需的子进程“免费提供”。所以,我得到了这个最小样本:

#include <iostream>

void callCmd(const std::string &cmd)
{
  system(cmd.c_str());
}

int main()
{
  std::cout << "My Linux Shell 1.0\n"
    << "Type exit[Enter] to exit.\n";
  for (;;) {
    std::cout << "> ";
    std::string input; std::getline(std::cin, input);
    if (input == "exit") return 0;
    callCmd(input);
  }
}

cygwin 上编译和测试在 Windows 10 上:

$ g++ -std=c++11 -o mycroShell mycroShell.cc 

$ ./mycroShell 
My Linux Shell 1.0
Type exit[Enter] to exit.
> echo "Hello"
Hello
> exit

$

运行后,callCmd() 中的 system() 调用可以替换为 fork()/exec ()/wait() 无需更改任何其他内容。


一个简化的版本可能是这样的:

#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void callCmd(const std::string &input)
{
  // the pre-processing: split the input into command and arguments
  std::string cmdArgs = input;
  std::vector<char*> args;
  char *cmd = &cmdArgs[0];
  args.push_back(cmd);
  for (char *c = cmd; *c; ++c) {
    if (*c == ' ') {
      *c = '\0'; args.push_back(c + 1);
    }
  }
  args.push_back(nullptr); // append terminator
  // simple replacement of system() (not that sophisticated)
  int ret = fork();
  if (ret < 0) { // failure
    std::cerr << "Failed to execute '" << cmd << "'!\n";
  } else if (ret == 0) { // child
    execvp(cmd, args.data());
  } else { // parent
    waitpid(ret, nullptr, 0);
  }
}

int main()
{
  std::cout << "My Linux Shell 1.1\n"
    << "Type exit[Enter] to exit.\n";
  for (;;) {
    std::cout << "> ";
    std::string input; std::getline(std::cin, input);
    if (input == "exit") return 0;
    callCmd(input);
  }
}

cygwin 上编译和测试再次在 Windows 10 上:

$ g++ -std=c++11 -o mycroShell mycroShell.cc 

$ ./mycroShell
My Linux Shell 1.1
Type exit[Enter] to exit.
> /usr/bin/echo "Hello"
"Hello"
> exit

$

注意事项:

  1. 恕我直言,其中最棘手的部分是为 execvp 准备一个合适的参数 vector 。

  2. 我也尝试使用 echo "Hello" 并且成功了。这让我有点吃惊,因为 echo 是一个 bash 内置命令。我假设它找到了 /usr/bin/echo 并在我上面的输出中使用了它。

  3. 错误处理相当差——对于严肃的应用程序应该扩展一些东西。

关于c++ - 如何停止执行第一个子进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51893883/

相关文章:

c++ - 如何将单个图像从图像 vector 复制到临时 cv::Mat?

c++ - fork 、管道和文件操作

c - 为什么我的信号处理程序执行两次?

使用 fork() 和 exec() 在终端中创建新命令

c++ - 将共享指针传递给函数参数 - 将其分配给局部变量的正确方法是什么

c++ - 继承抽象基接口(interface)及其实现给出 C2259

c++ - 通过指针访问非静态类成员函数的说明

c - fork() 内的 fork()

c - 以下 fork 程序的输出是什么?

c++ - 虚拟键码 : Same across ALL PC's