目标:设计一个 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
$
注意事项:
恕我直言,其中最棘手的部分是为
execvp
准备一个合适的参数 vector 。我也尝试使用
echo "Hello"
并且成功了。这让我有点吃惊,因为echo
是一个 bash 内置命令。我假设它找到了/usr/bin/echo
并在我上面的输出中使用了它。错误处理相当差——对于严肃的应用程序应该扩展一些东西。
关于c++ - 如何停止执行第一个子进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51893883/