У вас на востоке есть одна причина для неопределенного поведения, которое может заставить вашу программу делать то, что она делает.Вы объявляете и используете VLA вне диапазона, как это:
char* params[args.size()];
...
params[args.size()] = nullptr;
execv(image_path, params);
Это оставляет окончание char*
в вашем params
неинициализированным, так что оно может указывать куда угодно.grep
считает, что оно указывает на имя файла, пытается открыть его и не удается.
Поскольку VLA: s не соответствует стандарту C ++, рассмотрите возможность его изменения на:
std::vector<char*> params(args.size());
...
params[args.size() - 1] = nullptr;
execv(image_path, params.data());
Другоепричина для беспокойства заключается в том, что вы используете int
s там, где вы должны были использовать ssize_t
s, даже если очень маловероятно, что вы прочитали или написали больше, чем int
мог бы обработать.
После того, как я сделалте изменения, это начало работать и напечатало ожидаемое world
.Я даже добавил третью команду, чтобы убедиться, что она справится.Предлагаемые изменения:
14,15c14,15
< exec_cmd_t(std::vector<std::string> args) :
< args(args), has_executed(false), cpid(-1) {}
---
> exec_cmd_t(std::vector<std::string> Args) :
> args(Args), has_executed(false), cpid(-1), in_stream{}, out_stream{} {}
59c59
< int wr_sz = write(write_pipe[write_end], line.c_str(), line.size());
---
> ssize_t wr_sz = write(write_pipe[write_end], line.c_str(), line.size());
76c76
< char* params[args.size()];
---
> std::vector<char*> params(args.size());
78c78
< for(int i = 1; i < args.size(); i++) {
---
> for(decltype(args.size()) i = 1; i < args.size(); i++) {
81,82c81,82
< params[args.size()] = nullptr;
< execv(image_path, params);
---
> params[args.size() - 1] = nullptr;
> execv(image_path, params.data());
90c90
< int rd_sz = -1;
---
> ssize_t rd_sz = -1;
96c96
< int error_code = 0;
---
> // int error_code = 0; // unused
106,107c106
< static std::string empty_str{};
< return pipe_cmd(empty_str);
---
> return pipe_cmd({});
143c142,143
< exec_cmd_t{{"/bin/grep", "grep", "world", "-"}};
---
> exec_cmd_t{{"/bin/grep", "grep", "-A1", "hello"}} |
> exec_cmd_t{{"/bin/grep", "grep", "world"}};
Я также понял, что ваша программа действует как прокси между переданными командами, считывая все из одной команды и записывая ее в следующую.
Вы можете запустить все программы одновременно и настроить каналы между запущенными программами за один раз.Для трех команд вам понадобятся три канала:
cmd1 cmd2 cmd3
| w--r w--r |
stdin read output into program
or fed by your program
Это снизит производительность и потребление памяти, если вы решите запускать команды с большим количеством вывода.Внутренне вам нужно будет сохранить то, что вы хотите сохранить, прочитав вывод последней команды.Я сделал небольшой тест этого подхода, и он работает как шарм.