如何正确处理管道通道以实现管道命令(类似于linux中的管道命令)?
How to handle pipe channels correctly in order to implement pipe command (similar to pipe command in linux)?
我想实现一个管道命令(类似于 linux bash 中的这个),它基本上是这样工作的:
command1 | command2
:使用管道字符“|
”将产生一个管道,将 command1 stdout 重定向到它的写通道,将 command2 stdin 重定向到它的读通道。
或:
command1 |& command2
:使用管道字符“|&
”将产生一个管道,将 command1 stderr 重定向到管道的写入通道,将 command2 stdin 重定向到管道的读取通道。
现在命令 1 可以是来自 linux 的外部命令,我 运行 使用 execv 或我编写的内置命令,而命令 2 始终是外部命令
我的代码无法正常工作,我实现了很多命令并且它们都工作得很好,例如(cp、重定向...),所以我的代码中的基础是好的,但是管道是错误的!例如,如果命令是:showpid | ./parser.exe 1
其中 parser.exe 是一个对命令进行解析的给定文件,例如此处如果 showpid 打印:shell process pid is 12311
,则调用此命令 showpid | ./parser.exe 1
输出应为 "shell"
,但是在我的代码中,输出是 shell process pid is 12311
代码不工作的原因是我处理管道的通道和标准输入/标准输出错误!我几乎尝试了所有我认为可能的组合,但仍然有问题!
这是我的管道命令实现:
这是管道命令的 class :
class PipeCommand : public Command {
private:
int pipeNum;
int split;
string cmd1;
string cmd2;
public:
PipeCommand(const char* cmd_line);
virtual ~PipeCommand() {}
void execute() override;
};
// the pipe constructor , here i want to extract each command from the right and left side of the pipe from the cmd_line , which is the command line that i get
// fro example : " showpid | grep 1 "
PipeCommand::PipeCommand(const char* cmd_line):Command(cmd_line) {
pipeNum = -1;
isBackground = _isBackgroundComamnd(cmd_line);
string cmd1 = "", cmd2 = "";
int split = -1;
for (int i = 0; i < this->num_args; i++) {
if (strcmp(args[i], "|") == 0) {
split = i;
pipeNum = 1;
break;
}
if (strcmp(args[i], "|&") == 0) {
split = i;
pipeNum = 2;
break;
}
}
for (int i = 0; i < split; i++) {
cmd1 = cmd1 + args[i] + " ";
}
for (int i = split + 1; i < num_args; i++) {
cmd2 = cmd2 + args[i] + " ";
}
// the implementation of the pipe command
void PipeCommand::execute() {
int pipeFd[2];
int pid;
pipe(pipeFd);
pid = fork();
if (pid == 0) { // child process .
close(pipeFd[1]);
dup2(pipeFd[1], pipeNum);
if (isBuiltInCMD(args[0])) { // if the command is built in which means i wrote it i run it like this ( this works fine i checked it)
Command *newCmd = CreateBuiltInCommand(const_cast<char *>(cmd1.c_str()));
newCmd->execute();
exit(0);
} else { // if the command is external than use execv
const char **argv = new const char *[4];
argv[0] = "/bin/bash";
argv[1] = "-c";
argv[2] = cmd1.c_str();
argv[3] = nullptr;
execv(argv[0], const_cast<char **>(argv));
perror("execvp failed");
}
} else { // the parent process , basically runs the command2 , which it can be only an external command
pid = fork(); // we fork again in the parent process
if (pid == 0) { // the child process executes the secomd command using execv
dup2(pipeFd[0], STDIN_FILENO);
close(pipeFd[0]);
dup2(pipeFd[0], pipeNum);
// execute
const char **argv = new const char *[4];
argv[0] = "/bin/bash";
argv[1] = "-c";
argv[2] = cmd2.c_str();
argv[3] = nullptr;
execv(argv[0], const_cast<char **>(argv));
perror("execvp failed");
} else { // the parent process waits
waitpid(pid,NULL,0);
close(pipeFd[1]);
close(pipeFd[0]);
}
此代码生成管道,但我认为问题可能出在 Parser.exe
程序未获取第一个单词,而是所有输入。
int main(int argc, char** argv)
{
int pipes[2] {0};
int pid {0};
if (argc < 3) {
printf ("No file to cat and/or no text to grep.\n");
return 1;
}
pipe (pipes);
pid = fork();
if (pid == 0) {
dup2 (pipes[1], STDOUT_FILENO);
close (pipes[1]);
close (pipes[0]);
execl ("/bin/cat", "/bin/cat", argv[1], nullptr);
} else {
int pid = fork();
if (pid == 0) {
dup2 (pipes[0], STDIN_FILENO);
close (pipes[1]);
close (pipes[0]);
execl ("/bin/grep", "/bin/grep", argv[2], nullptr);
} else {
close (pipes[0]);
close (pipes[1]);
waitpid (pid, nullptr, 0);
}
}
return 0;
}
它正在运行,但您可能需要适应您的 class。
这是我的输出:
manuel@desktop:~/projects$ ./main sync_client.cpp boost
Going to cat sync_client.cpp
Going to grep for boost
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
std::cout << " sync_client www.boost.org /LICENSE_1_0.txt\n";
boost::asio::io_service io_service;
boost::system::error_code error = boost::asio::error::host_not_found;
throw boost::system::system_error(error);
boost::asio::streambuf request;
boost::asio::write(socket, request);
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
boost::asio::read_until(socket, response, "\r\n\r\n");
while (boost::asio::read(socket, response,
boost::asio::transfer_at_least(1), error))
if (error != boost::asio::error::eof)
throw boost::system::system_error(error);
我想实现一个管道命令(类似于 linux bash 中的这个),它基本上是这样工作的:
command1 | command2
:使用管道字符“|
”将产生一个管道,将 command1 stdout 重定向到它的写通道,将 command2 stdin 重定向到它的读通道。
或:
command1 |& command2
:使用管道字符“|&
”将产生一个管道,将 command1 stderr 重定向到管道的写入通道,将 command2 stdin 重定向到管道的读取通道。
现在命令 1 可以是来自 linux 的外部命令,我 运行 使用 execv 或我编写的内置命令,而命令 2 始终是外部命令
我的代码无法正常工作,我实现了很多命令并且它们都工作得很好,例如(cp、重定向...),所以我的代码中的基础是好的,但是管道是错误的!例如,如果命令是:showpid | ./parser.exe 1
其中 parser.exe 是一个对命令进行解析的给定文件,例如此处如果 showpid 打印:shell process pid is 12311
,则调用此命令 showpid | ./parser.exe 1
输出应为 "shell"
,但是在我的代码中,输出是 shell process pid is 12311
代码不工作的原因是我处理管道的通道和标准输入/标准输出错误!我几乎尝试了所有我认为可能的组合,但仍然有问题!
这是我的管道命令实现:
这是管道命令的 class :
class PipeCommand : public Command {
private:
int pipeNum;
int split;
string cmd1;
string cmd2;
public:
PipeCommand(const char* cmd_line);
virtual ~PipeCommand() {}
void execute() override;
};
// the pipe constructor , here i want to extract each command from the right and left side of the pipe from the cmd_line , which is the command line that i get
// fro example : " showpid | grep 1 "
PipeCommand::PipeCommand(const char* cmd_line):Command(cmd_line) {
pipeNum = -1;
isBackground = _isBackgroundComamnd(cmd_line);
string cmd1 = "", cmd2 = "";
int split = -1;
for (int i = 0; i < this->num_args; i++) {
if (strcmp(args[i], "|") == 0) {
split = i;
pipeNum = 1;
break;
}
if (strcmp(args[i], "|&") == 0) {
split = i;
pipeNum = 2;
break;
}
}
for (int i = 0; i < split; i++) {
cmd1 = cmd1 + args[i] + " ";
}
for (int i = split + 1; i < num_args; i++) {
cmd2 = cmd2 + args[i] + " ";
}
// the implementation of the pipe command
void PipeCommand::execute() {
int pipeFd[2];
int pid;
pipe(pipeFd);
pid = fork();
if (pid == 0) { // child process .
close(pipeFd[1]);
dup2(pipeFd[1], pipeNum);
if (isBuiltInCMD(args[0])) { // if the command is built in which means i wrote it i run it like this ( this works fine i checked it)
Command *newCmd = CreateBuiltInCommand(const_cast<char *>(cmd1.c_str()));
newCmd->execute();
exit(0);
} else { // if the command is external than use execv
const char **argv = new const char *[4];
argv[0] = "/bin/bash";
argv[1] = "-c";
argv[2] = cmd1.c_str();
argv[3] = nullptr;
execv(argv[0], const_cast<char **>(argv));
perror("execvp failed");
}
} else { // the parent process , basically runs the command2 , which it can be only an external command
pid = fork(); // we fork again in the parent process
if (pid == 0) { // the child process executes the secomd command using execv
dup2(pipeFd[0], STDIN_FILENO);
close(pipeFd[0]);
dup2(pipeFd[0], pipeNum);
// execute
const char **argv = new const char *[4];
argv[0] = "/bin/bash";
argv[1] = "-c";
argv[2] = cmd2.c_str();
argv[3] = nullptr;
execv(argv[0], const_cast<char **>(argv));
perror("execvp failed");
} else { // the parent process waits
waitpid(pid,NULL,0);
close(pipeFd[1]);
close(pipeFd[0]);
}
此代码生成管道,但我认为问题可能出在 Parser.exe
程序未获取第一个单词,而是所有输入。
int main(int argc, char** argv)
{
int pipes[2] {0};
int pid {0};
if (argc < 3) {
printf ("No file to cat and/or no text to grep.\n");
return 1;
}
pipe (pipes);
pid = fork();
if (pid == 0) {
dup2 (pipes[1], STDOUT_FILENO);
close (pipes[1]);
close (pipes[0]);
execl ("/bin/cat", "/bin/cat", argv[1], nullptr);
} else {
int pid = fork();
if (pid == 0) {
dup2 (pipes[0], STDIN_FILENO);
close (pipes[1]);
close (pipes[0]);
execl ("/bin/grep", "/bin/grep", argv[2], nullptr);
} else {
close (pipes[0]);
close (pipes[1]);
waitpid (pid, nullptr, 0);
}
}
return 0;
}
它正在运行,但您可能需要适应您的 class。
这是我的输出:
manuel@desktop:~/projects$ ./main sync_client.cpp boost
Going to cat sync_client.cpp
Going to grep for boost
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
std::cout << " sync_client www.boost.org /LICENSE_1_0.txt\n";
boost::asio::io_service io_service;
boost::system::error_code error = boost::asio::error::host_not_found;
throw boost::system::system_error(error);
boost::asio::streambuf request;
boost::asio::write(socket, request);
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
boost::asio::read_until(socket, response, "\r\n\r\n");
while (boost::asio::read(socket, response,
boost::asio::transfer_at_least(1), error))
if (error != boost::asio::error::eof)
throw boost::system::system_error(error);