Это немного сложнее, чем кажется в начале. Следует соблюдать несколько правил:
Символ вертикальной черты не может следовать сам по себе (иначе они образуют оператор ||
).
Помните побегов.
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/')"
.