目标:设计一个Linux外壳程序,其中显示提示用户输入信息,创建一个新进程来执行该命令,然后终止/退出该进程。这是我的代码
#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>执行
在程序运行时显示在第一行,而不仅仅是
myShell>
。 我能够理解为什么会发生这种情况,但无法弄清楚如何停止执行第一个子进程。 请为我提出解决问题的方法/解决方案。
编辑1:这是我的作业之一(用于学习UNIX进程) 问题,并且明确指出该程序“会提示 用户使用命令,解析该命令,然后使用 子进程“
答案 0 :(得分:2)
正如我已经猜到的,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);
}
}
已在Windows 10的cygwin上进行了编译和测试:
$ g++ -std=c++11 -o mycroShell mycroShell.cc
$ ./mycroShell
My Linux Shell 1.0
Type exit[Enter] to exit.
> echo "Hello"
Hello
> exit
$
运行此命令后,system()
中的callCmd()
调用可以替换为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);
}
}
再次在Windows 10的cygwin上进行编译和测试:
$ 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
准备适当的参数向量。
我也尝试了echo "Hello"
,它也有效。 echo
是bash内置命令,这让我有些惊讶。我假设它找到了/usr/bin/echo
并在上面的输出中使用了它。
错误处理能力很差-对于严重的应用程序应该进行扩展。