Как я смогу передать несколько команд с помощью этой программы? C ++ - PullRequest
0 голосов
/ 19 июня 2020

Я нашел это { ссылка } решение для текущего задания. Тем не менее, я впервые работаю с конвейерами на C ++. Так что я все еще относительно новичок во всем этом. Мне было любопытно, если бы я хотел изменить эту программу, чтобы иметь возможность обрабатывать несколько каналов, как именно я смогу подсчитать их количество? Я понимаю, что переменная ptr является токеном, но не выполняются ли команды по мере их анализа? Как я смогу пересчитать все трубы перед казнью? Я ищу возможность выполнить что-то подобное до конца

cat text.txt | sort | tail -3 | grep thankyou

Ответы [ 2 ]

1 голос
/ 19 июня 2020

Это немного сложнее, чем кажется в начале. Следует соблюдать несколько правил:

  1. Символ вертикальной черты не может следовать сам по себе (иначе они образуют оператор ||).

  2. Помните побегов.

2а. Какие строки являются самыми опасными.

Допустим, мы могли бы реализовать частично функциональную версию, так как

std::string command{"cat text.txt | sort | tail -3 | grep thankyou"};
std::size_t count{};
for(auto pos = command.find_first_of("|\\\"'"); pos != command.npos;
         pos = command.find_first_of("|\\\"'", pos + 1))
{
    switch(command[pos]) {
        // a pipe char not followed by a pipe char is actually what we're looking for
        case '|': if(pos < command.size() - 1 && command[pos + 1] == '|')
                  {
                      ++pos; // ||
                  }
                  else ++count; // a real pipe
                  break
        // a plain one-char escape
        case '\\': ++pos;
                   break;
        case '\'': // iirc, there's no escape chars in singly-quoted strings
                   // skip until next '
                   pos = command.find('\'', pos + 1);
                   break;
        default: // a doubly-quoted string
                 pos = find_closing(command, pos);
    }
}

find_closing должен использовать строки в кавычках, если они есть.

std::string::size_type find_closing(std::string const &cmd, std::size_t pos) {
    for(auto nxt = cmd.find_first_of("\"\\", pos + 1); nxt != cmd.npos;
             nxt = cmd.find_first_of("\"\\", nxt + 2))
    {
        if(cmd[nxt] == '"') return nxt; // unescaped closing double quote
    }
    return cmd.npos;
}

Может потребоваться некоторая отладка.

Этот код не обрабатывает очень сложные случаи, такие как echo "$(echo 123 | sed 's/2/4/')".

0 голосов
/ 19 июня 2020

Предположим, у вас есть эта строка в std::string:

using Command = std::vector<std::string>;
using Pipeline = std::vector<Command>;

Pipeline p;
Command c;
std::istringstream iss(line);
while (true) {
  std::string token;
  iss >> token;
  if (iss.eof()) {
    // Nothing more to read. Push the last command to the pipeline, if any.
    if (!c.empty()) {
      p.push_back(c);
    }
    break;
  }

  if (token == '|') {
    // We saw a pipe. Push the current command to the pipeline and
    // start parsing a new one.
    p.push_back(c);
    c.clear();
  } else {
    // This is a regular part of a command
    c.push_back(token);
  }
}

В конце p будет иметь следующую форму:

[
  ["cat", "text.txt"],
  ["sort"],
  ["tail", -3],
  ["grep", "thankyou"]
]
...